Create an upgrade command
This command will assist users with migration from 1.x.x to 2.0.0.
This commit is contained in:
parent
0c9468c9b5
commit
b62a4c77a6
5 changed files with 219 additions and 22 deletions
|
@ -84,6 +84,7 @@ def supported_commands():
|
||||||
'introspect',
|
'introspect',
|
||||||
'list',
|
'list',
|
||||||
'perms',
|
'perms',
|
||||||
|
'upgrade',
|
||||||
'version',
|
'version',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -10,25 +10,30 @@ import pytest
|
||||||
'encrypt',
|
'encrypt',
|
||||||
'files.gpg',
|
'files.gpg',
|
||||||
'bootstrap',
|
'bootstrap',
|
||||||
'hooks',
|
'hooks/pre_command',
|
||||||
|
'hooks/post_command',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_legacy_warning(tmpdir, runner, yadm, legacy_path):
|
@pytest.mark.parametrize(
|
||||||
|
'upgrade', [True, False], ids=['upgrade', 'no-upgrade'])
|
||||||
|
def test_legacy_warning(tmpdir, runner, yadm, upgrade, legacy_path):
|
||||||
"""Use issue_legacy_path_warning"""
|
"""Use issue_legacy_path_warning"""
|
||||||
home = tmpdir.mkdir('home')
|
home = tmpdir.mkdir('home')
|
||||||
|
|
||||||
if legacy_path:
|
if legacy_path:
|
||||||
home.mkdir(f'.yadm').mkdir(legacy_path)
|
home.mkdir(f'.yadm').ensure(legacy_path)
|
||||||
|
|
||||||
|
main_args = 'MAIN_ARGS=("upgrade")' if upgrade else ''
|
||||||
script = f"""
|
script = f"""
|
||||||
HOME={home}
|
HOME={home}
|
||||||
YADM_TEST=1 source {yadm}
|
YADM_TEST=1 source {yadm}
|
||||||
|
{main_args}
|
||||||
issue_legacy_path_warning
|
issue_legacy_path_warning
|
||||||
"""
|
"""
|
||||||
run = runner(command=['bash'], inp=script)
|
run = runner(command=['bash'], inp=script)
|
||||||
assert run.success
|
assert run.success
|
||||||
assert run.err == ''
|
assert run.err == ''
|
||||||
if legacy_path:
|
if legacy_path and not upgrade:
|
||||||
assert 'Legacy configuration paths have been detected' in run.out
|
assert 'Legacy configuration paths have been detected' in run.out
|
||||||
else:
|
else:
|
||||||
assert run.out.rstrip() == ''
|
assert run.out.rstrip() == ''
|
||||||
|
|
101
test/test_unit_upgrade.py
Normal file
101
test/test_unit_upgrade.py
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
"""Unit tests: upgrade"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
LEGACY_PATHS = [
|
||||||
|
'config',
|
||||||
|
'encrypt',
|
||||||
|
'files.gpg',
|
||||||
|
'bootstrap',
|
||||||
|
'hooks/pre_command',
|
||||||
|
'hooks/post_command',
|
||||||
|
]
|
||||||
|
|
||||||
|
# used:
|
||||||
|
# YADM_COMPATIBILITY
|
||||||
|
# YADM_DIR
|
||||||
|
# YADM_LEGACY_DIR
|
||||||
|
# GIT_PROGRAM
|
||||||
|
@pytest.mark.parametrize('condition', ['compat', 'equal', 'existing_repo'])
|
||||||
|
def test_upgrade_errors(tmpdir, runner, yadm, condition):
|
||||||
|
"""Test upgrade() error conditions"""
|
||||||
|
|
||||||
|
compatibility = 'YADM_COMPATIBILITY=1' if condition == 'compat' else ''
|
||||||
|
|
||||||
|
home = tmpdir.mkdir('home')
|
||||||
|
yadm_dir = home.join('.config/yadm')
|
||||||
|
legacy_dir = home.join('.yadm')
|
||||||
|
if condition == 'equal':
|
||||||
|
legacy_dir = yadm_dir
|
||||||
|
if condition == 'existing_repo':
|
||||||
|
yadm_dir.ensure_dir('repo.git')
|
||||||
|
legacy_dir.ensure_dir('repo.git')
|
||||||
|
|
||||||
|
script = f"""
|
||||||
|
YADM_TEST=1 source {yadm}
|
||||||
|
{compatibility}
|
||||||
|
YADM_DIR="{yadm_dir}"
|
||||||
|
YADM_REPO="{yadm_dir}/repo.git"
|
||||||
|
YADM_LEGACY_DIR="{legacy_dir}"
|
||||||
|
upgrade
|
||||||
|
"""
|
||||||
|
run = runner(command=['bash'], inp=script)
|
||||||
|
assert run.failure
|
||||||
|
assert run.err == ''
|
||||||
|
assert 'Unable to upgrade' in run.out
|
||||||
|
if condition == 'compat':
|
||||||
|
assert 'YADM_COMPATIBILITY' in run.out
|
||||||
|
if condition == 'equal':
|
||||||
|
assert 'has been resolved as' in run.out
|
||||||
|
if condition == 'existing_repo':
|
||||||
|
assert 'already exists' in run.out
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('condition', ['no-paths', 'untracked', 'tracked'])
|
||||||
|
def test_upgrade(tmpdir, runner, yadm, condition):
|
||||||
|
"""Test upgrade()
|
||||||
|
|
||||||
|
When testing the condition of git-tracked data, "echo" will be used as a
|
||||||
|
mock for git. echo will return true, simulating a positive result from "git
|
||||||
|
ls-files". Also echo will report the parameters for "git mv".
|
||||||
|
"""
|
||||||
|
home = tmpdir.mkdir('home')
|
||||||
|
yadm_dir = home.join('.config/yadm')
|
||||||
|
legacy_dir = home.join('.yadm')
|
||||||
|
|
||||||
|
if condition != 'no-paths':
|
||||||
|
legacy_dir.join('repo.git/config').write('test-repo', ensure=True)
|
||||||
|
for lpath in LEGACY_PATHS:
|
||||||
|
legacy_dir.join(lpath).write(lpath, ensure=True)
|
||||||
|
|
||||||
|
git = 'echo' if condition == 'tracked' else 'git'
|
||||||
|
|
||||||
|
script = f"""
|
||||||
|
YADM_TEST=1 source {yadm}
|
||||||
|
YADM_DIR="{yadm_dir}"
|
||||||
|
YADM_REPO="{yadm_dir}/repo.git"
|
||||||
|
YADM_LEGACY_DIR="{legacy_dir}"
|
||||||
|
GIT_PROGRAM="{git}"
|
||||||
|
upgrade
|
||||||
|
"""
|
||||||
|
run = runner(command=['bash'], inp=script)
|
||||||
|
assert run.success
|
||||||
|
assert run.err == ''
|
||||||
|
if condition == 'no-paths':
|
||||||
|
assert 'Upgrade is not necessary' in run.out
|
||||||
|
else:
|
||||||
|
for lpath in LEGACY_PATHS + ['repo.git']:
|
||||||
|
expected = (
|
||||||
|
f'Moving {legacy_dir.join(lpath)} '
|
||||||
|
f'to {yadm_dir.join(lpath)}')
|
||||||
|
assert expected in run.out
|
||||||
|
if condition == 'untracked':
|
||||||
|
assert 'test-repo' in yadm_dir.join('repo.git/config').read()
|
||||||
|
for lpath in LEGACY_PATHS:
|
||||||
|
assert lpath in yadm_dir.join(lpath).read()
|
||||||
|
elif condition == 'tracked':
|
||||||
|
for lpath in LEGACY_PATHS:
|
||||||
|
expected = (
|
||||||
|
f'mv {legacy_dir.join(lpath)} '
|
||||||
|
f'{yadm_dir.join(lpath)}')
|
||||||
|
assert expected in run.out
|
||||||
|
assert 'files tracked by yadm have been renamed' in run.out
|
100
yadm
100
yadm
|
@ -72,7 +72,7 @@ function main() {
|
||||||
|
|
||||||
# parse command line arguments
|
# parse command line arguments
|
||||||
local retval=0
|
local retval=0
|
||||||
internal_commands="^(alt|bootstrap|clean|clone|config|decrypt|encrypt|enter|help|init|introspect|list|perms|version)$"
|
internal_commands="^(alt|bootstrap|clean|clone|config|decrypt|encrypt|enter|help|init|introspect|list|perms|upgrade|version)$"
|
||||||
if [ -z "$*" ] ; then
|
if [ -z "$*" ] ; then
|
||||||
# no argumnts will result in help()
|
# no argumnts will result in help()
|
||||||
help
|
help
|
||||||
|
@ -505,13 +505,12 @@ function alt_future_linking() {
|
||||||
filename="${alt_filenames[$index]}"
|
filename="${alt_filenames[$index]}"
|
||||||
target="${alt_targets[$index]}"
|
target="${alt_targets[$index]}"
|
||||||
template_cmd="${alt_template_cmds[$index]}"
|
template_cmd="${alt_template_cmds[$index]}"
|
||||||
basedir=${filename%/*}
|
|
||||||
if [ -n "$template_cmd" ]; then
|
if [ -n "$template_cmd" ]; then
|
||||||
# a template is defined, process the template
|
# a template is defined, process the template
|
||||||
debug "Creating $filename from template $target"
|
debug "Creating $filename from template $target"
|
||||||
[ -n "$loud" ] && echo "Creating $filename from template $target"
|
[ -n "$loud" ] && echo "Creating $filename from template $target"
|
||||||
# ensure the destination path exists
|
# ensure the destination path exists
|
||||||
[ -e "$basedir" ] || mkdir -p "$basedir"
|
assert_parent "$filename"
|
||||||
# remove any existing symlink before processing template
|
# remove any existing symlink before processing template
|
||||||
[ -L "$filename" ] && rm -f "$filename"
|
[ -L "$filename" ] && rm -f "$filename"
|
||||||
"$template_cmd" "$target" "$filename"
|
"$template_cmd" "$target" "$filename"
|
||||||
|
@ -520,7 +519,7 @@ function alt_future_linking() {
|
||||||
debug "Linking $target to $filename"
|
debug "Linking $target to $filename"
|
||||||
[ -n "$loud" ] && echo "Linking $target to $filename"
|
[ -n "$loud" ] && echo "Linking $target to $filename"
|
||||||
# ensure the destination path exists
|
# ensure the destination path exists
|
||||||
[ -e "$basedir" ] || mkdir -p "$basedir"
|
assert_parent "$filename"
|
||||||
if [ "$do_copy" -eq 1 ]; then
|
if [ "$do_copy" -eq 1 ]; then
|
||||||
# remove any existing symlink before copying
|
# remove any existing symlink before copying
|
||||||
[ -L "$filename" ] && rm -f "$filename"
|
[ -L "$filename" ] && rm -f "$filename"
|
||||||
|
@ -975,6 +974,7 @@ init
|
||||||
introspect
|
introspect
|
||||||
list
|
list
|
||||||
perms
|
perms
|
||||||
|
upgrade
|
||||||
version
|
version
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
@ -1062,6 +1062,66 @@ function perms() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function upgrade() {
|
||||||
|
|
||||||
|
local actions_performed
|
||||||
|
actions_performed=0
|
||||||
|
local repo_updates
|
||||||
|
repo_updates=0
|
||||||
|
|
||||||
|
[ "$YADM_COMPATIBILITY" = "1" ] && \
|
||||||
|
error_out "Unable to upgrade. YADM_COMPATIBILITY is set to '1'."
|
||||||
|
|
||||||
|
[ "$YADM_DIR" = "$YADM_LEGACY_DIR" ] && \
|
||||||
|
error_out "Unable to upgrade. yadm dir has been resolved as '$YADM_LEGACY_DIR'."
|
||||||
|
|
||||||
|
# handle legacy repo
|
||||||
|
if [ -d "$YADM_LEGACY_DIR/repo.git" ]; then
|
||||||
|
# legacy repo detected, it must be moved to YADM_REPO
|
||||||
|
if [ -e "$YADM_REPO" ]; then
|
||||||
|
error_out "Unable to upgrade. '$YADM_REPO' already exists. Refusing to overwrite it."
|
||||||
|
else
|
||||||
|
actions_performed=1
|
||||||
|
echo "Moving $YADM_LEGACY_DIR/repo.git to $YADM_REPO"
|
||||||
|
assert_parent "$YADM_REPO"
|
||||||
|
mv "$YADM_LEGACY_DIR/repo.git" "$YADM_REPO"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# handle other legacy paths
|
||||||
|
for legacy_path in \
|
||||||
|
"$YADM_LEGACY_DIR/config" \
|
||||||
|
"$YADM_LEGACY_DIR/encrypt" \
|
||||||
|
"$YADM_LEGACY_DIR/files.gpg" \
|
||||||
|
"$YADM_LEGACY_DIR/bootstrap" \
|
||||||
|
"$YADM_LEGACY_DIR"/hooks/{pre,post}_* \
|
||||||
|
; \
|
||||||
|
do
|
||||||
|
if [ -e "$legacy_path" ]; then
|
||||||
|
new_filename=${legacy_path#$YADM_LEGACY_DIR/}
|
||||||
|
new_filename="$YADM_DIR/$new_filename"
|
||||||
|
actions_performed=1
|
||||||
|
echo "Moving $legacy_path to $new_filename"
|
||||||
|
assert_parent "$new_filename"
|
||||||
|
# test to see if path is "tracked" in repo, if so 'git mv' must be used
|
||||||
|
if GIT_DIR="$YADM_REPO" "$GIT_PROGRAM" ls-files --error-unmatch "$legacy_path" >/dev/null 2>&1; then
|
||||||
|
GIT_DIR="$YADM_REPO" "$GIT_PROGRAM" mv "$legacy_path" "$new_filename" && repo_updates=1
|
||||||
|
else
|
||||||
|
mv -i "$legacy_path" "$new_filename"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
[ "$actions_performed" -eq 0 ] && \
|
||||||
|
echo "No legacy paths found. Upgrade is not necessary"
|
||||||
|
|
||||||
|
[ "$repo_updates" -eq 1 ] && \
|
||||||
|
echo "Some files tracked by yadm have been renamed. This changes should probably be commited now."
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function version() {
|
function version() {
|
||||||
|
|
||||||
echo "yadm $VERSION"
|
echo "yadm $VERSION"
|
||||||
|
@ -1110,9 +1170,8 @@ function exclude_encrypted() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${exclude_header}${encrypt_data}" != "$managed" ]; then
|
if [ "${exclude_header}${encrypt_data}" != "$managed" ]; then
|
||||||
basedir=${exclude_path%/*}
|
|
||||||
[ -e "$basedir" ] || mkdir -p "$basedir" # assert path
|
|
||||||
debug "Updating ${exclude_path}"
|
debug "Updating ${exclude_path}"
|
||||||
|
assert_parent "$exclude_path"
|
||||||
printf "%s" "${unmanaged}${exclude_header}${encrypt_data}" > "$exclude_path"
|
printf "%s" "${unmanaged}${exclude_header}${encrypt_data}" > "$exclude_path"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -1221,6 +1280,9 @@ function set_yadm_dir() {
|
||||||
|
|
||||||
function issue_legacy_path_warning() {
|
function issue_legacy_path_warning() {
|
||||||
|
|
||||||
|
# no warnings during upgrade
|
||||||
|
[[ "${MAIN_ARGS[*]}" =~ upgrade ]] && return
|
||||||
|
|
||||||
# no warnings if YADM_DIR is resolved as the leacy path
|
# no warnings if YADM_DIR is resolved as the leacy path
|
||||||
[ "$YADM_DIR" = "$YADM_LEGACY_DIR" ] && return
|
[ "$YADM_DIR" = "$YADM_LEGACY_DIR" ] && return
|
||||||
|
|
||||||
|
@ -1231,14 +1293,14 @@ function issue_legacy_path_warning() {
|
||||||
local legacy_found
|
local legacy_found
|
||||||
legacy_found=()
|
legacy_found=()
|
||||||
# this is ordered by importance
|
# this is ordered by importance
|
||||||
for legacy_path in \
|
for legacy_path in \
|
||||||
"$YADM_LEGACY_DIR/$YADM_REPO" \
|
"$YADM_LEGACY_DIR/$YADM_REPO" \
|
||||||
"$YADM_LEGACY_DIR/$YADM_CONFIG" \
|
"$YADM_LEGACY_DIR/$YADM_CONFIG" \
|
||||||
"$YADM_LEGACY_DIR/$YADM_ENCRYPT" \
|
"$YADM_LEGACY_DIR/$YADM_ENCRYPT" \
|
||||||
"$YADM_LEGACY_DIR/$YADM_ARCHIVE" \
|
"$YADM_LEGACY_DIR/$YADM_ARCHIVE" \
|
||||||
"$YADM_LEGACY_DIR/$YADM_BOOTSTRAP" \
|
"$YADM_LEGACY_DIR/$YADM_BOOTSTRAP" \
|
||||||
"$YADM_LEGACY_DIR/$YADM_HOOKS" \
|
"$YADM_LEGACY_DIR/$YADM_HOOKS"/{pre,post}_* \
|
||||||
; \
|
; \
|
||||||
do
|
do
|
||||||
[ -e "$legacy_path" ] && legacy_found+=("$legacy_path")
|
[ -e "$legacy_path" ] && legacy_found+=("$legacy_path")
|
||||||
done
|
done
|
||||||
|
@ -1258,14 +1320,15 @@ function issue_legacy_path_warning() {
|
||||||
Beginning with version 2.0.0, yadm uses the XDG Base Directory Specification
|
Beginning with version 2.0.0, yadm uses the XDG Base Directory Specification
|
||||||
to find its configurations. Read more about this change here:
|
to find its configurations. Read more about this change here:
|
||||||
|
|
||||||
https://yadm.io/docs/xdg_config_home
|
https://yadm.io/docs/upgrade_from_1.x.x
|
||||||
|
|
||||||
In your environment, the configuration directory has been resolved to:
|
In your environment, the configuration directory has been resolved to:
|
||||||
|
|
||||||
$YADM_DIR
|
$YADM_DIR
|
||||||
|
|
||||||
To remove this warning do one of the following:
|
To remove this warning do one of the following:
|
||||||
* Move yadm configurations to the directory listed above. (RECOMMENDED)
|
* Run "yadm upgrade" to move the yadm data to the new directory. (RECOMMENDED)
|
||||||
|
* Manually move yadm configurations to the directory listed above.
|
||||||
* Specify your preferred yadm directory with -Y each execution.
|
* Specify your preferred yadm directory with -Y each execution.
|
||||||
* Define an environment variable "YADM_COMPATIBILITY=1" to run in version 1
|
* Define an environment variable "YADM_COMPATIBILITY=1" to run in version 1
|
||||||
compatibility mode. (DEPRECATED)
|
compatibility mode. (DEPRECATED)
|
||||||
|
@ -1421,6 +1484,11 @@ function assert_private_dirs() {
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function assert_parent() {
|
||||||
|
basedir=${1%/*}
|
||||||
|
[ -e "$basedir" ] || mkdir -p "$basedir"
|
||||||
|
}
|
||||||
|
|
||||||
function display_private_perms() {
|
function display_private_perms() {
|
||||||
when="$1"
|
when="$1"
|
||||||
for private_dir in .ssh .gnupg; do
|
for private_dir in .ssh .gnupg; do
|
||||||
|
|
26
yadm.1
26
yadm.1
|
@ -56,6 +56,8 @@ list
|
||||||
|
|
||||||
.BR yadm " perms
|
.BR yadm " perms
|
||||||
|
|
||||||
|
.BR yadm " upgrade
|
||||||
|
|
||||||
.BR yadm " introspect
|
.BR yadm " introspect
|
||||||
.I category
|
.I category
|
||||||
|
|
||||||
|
@ -255,6 +257,22 @@ configuration
|
||||||
.I yadm.auto-perms
|
.I yadm.auto-perms
|
||||||
to "false".
|
to "false".
|
||||||
.TP
|
.TP
|
||||||
|
.B upgrade
|
||||||
|
Version 2 of yadm uses a different directory for storing your configurations.
|
||||||
|
When you start to use version 2 for the first time, you may see warnings about
|
||||||
|
moving your data to this new directory.
|
||||||
|
The easiest way to accomplish this is by running "yadm upgrade".
|
||||||
|
This command will start by moving your yadm repo to the new path.
|
||||||
|
Next it will move any configuration data to the new path.
|
||||||
|
If the configurations are tracked within your yadm repo, this command will
|
||||||
|
"stage" the renaming of those files in the repo's index.
|
||||||
|
After running "yadm upgrade", you should run "yadm status" to review changes
|
||||||
|
which have been staged, and commit them to your repository.
|
||||||
|
|
||||||
|
You can read
|
||||||
|
https://yadm.io/docs/upgrade_from_1.x.x
|
||||||
|
for more information.
|
||||||
|
.TP
|
||||||
.B version
|
.B version
|
||||||
Print the version of yadm.
|
Print the version of yadm.
|
||||||
|
|
||||||
|
@ -262,10 +280,14 @@ Print the version of yadm.
|
||||||
|
|
||||||
Beginning with version 2.0.0, yadm introduced a couple major changes which may
|
Beginning with version 2.0.0, yadm introduced a couple major changes which may
|
||||||
require you to adjust your configurations.
|
require you to adjust your configurations.
|
||||||
|
See the
|
||||||
|
.B upgrade
|
||||||
|
command for help making those adjustments.
|
||||||
|
|
||||||
First, yadm now uses the "XDG Base Directory Specification" to find its
|
First, yadm now uses the "XDG Base Directory Specification" to find its
|
||||||
configurations. You can read https://yadm.io/docs/xdg_config_home for more
|
configurations. You can read
|
||||||
information.
|
https://yadm.io/docs/upgrade_from_1.x.x
|
||||||
|
for more information.
|
||||||
|
|
||||||
Second, the naming conventions for alternate files have been changed.
|
Second, the naming conventions for alternate files have been changed.
|
||||||
You can read https://yadm.io/docs/alternates for more information.
|
You can read https://yadm.io/docs/alternates for more information.
|
||||||
|
|
Loading…
Reference in a new issue