|
| 1 | +#!/bin/sh |
| 2 | +# Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. |
| 3 | + |
| 4 | +# This script generates a patch by comparing the contents of the fsharp/fsharp |
| 5 | +# and Microsoft/visualfsharp Github repositories. The resulting patch can be applied, |
| 6 | +# if desired, to one of the repositories to synchronize changes in one direction; |
| 7 | +# CAUTION MUST BE TAKEN though, since this script generates the patch in a way that |
| 8 | +# ignores any ordering of commits in the repos -- so it could also end up reverting |
| 9 | +# changes that were actually needed. |
| 10 | +# The produced patch is primarily useful for examining differences between two repos |
| 11 | +# and making it easier to submit targeted PRs to manually synchronize changes. |
| 12 | + |
| 13 | +# Helper function to clean up after we're done (or if there's an error). |
| 14 | +cleanup () { |
| 15 | + # Leave the working directory, then delete it. |
| 16 | + { popd && rm -rf "$tmpdir"; } || printf "Unable to clean up temp directory '%s'\n" "$tmpdir" |
| 17 | +} |
| 18 | + |
| 19 | +# Helper function to print an error message and exit with a non-zero error code. |
| 20 | +failwith () { |
| 21 | + printf "Error: %s\n" "$1" >&2 |
| 22 | + cleanup |
| 23 | + exit 1 |
| 24 | +} |
| 25 | + |
| 26 | +# Delete the .git folder from a folder containing an extracted/cloned repository. |
| 27 | +remove_git () { |
| 28 | + { pushd "$1" && rm -rf .git && popd; } || \ |
| 29 | + { printf "Error: Couldn't remove .git from '%s'\n" "$1"; cleanup_error; } |
| 30 | +} |
| 31 | + |
| 32 | +# Delete "don't care" files from a folder containing an extracted/cloned repository. |
| 33 | +# These are files with known differences between the two repos, but where we don't care |
| 34 | +# about those differences for the purposes of generating a patch. |
| 35 | +remove_irrelevant_files () { |
| 36 | + if pushd "$1"; then |
| 37 | + # TODO: Use 'for in _ do' syntax here instead? Maybe read the list from a separate text file? |
| 38 | + # If any of the files in here can't be removed, ignore the failure and keep going. |
| 39 | + rm .travis.yml |
| 40 | + rm CHANGELOG.md |
| 41 | + rm CONTRIBUTING.md |
| 42 | + rm README.md |
| 43 | + |
| 44 | + popd |
| 45 | + fi |
| 46 | +} |
| 47 | + |
| 48 | +# Options for controlling the behavior of this script. |
| 49 | +tmpdir="diff_tmp" # name of temp folder to create and work in |
| 50 | +fetch_source_by_cloning=1 # git diff doesn't seem to like curl+tar, so clone with git for now. |
| 51 | +github_org1="fsharp" |
| 52 | +github_repo1="fsharp" |
| 53 | +github_org2="Microsoft" |
| 54 | +github_repo2="visualfsharp" |
| 55 | +repo_dir1="${github_org1}_${github_repo1}" |
| 56 | +repo_dir2="${github_org2}_${github_repo2}" |
| 57 | +include_all_changes=0 # If set to 1, file additions/deletions will also be included in the patch. |
| 58 | +patch_path="../${github_repo1}-${github_repo2}.patch" |
| 59 | + |
| 60 | +# Create a temporary directory to work in. |
| 61 | +if ! mkdir "$tmpdir"; then |
| 62 | + printf "Unable to create temp directory '%s' (does it already exist?)\n" "$tmpdir" |
| 63 | + exit 1 |
| 64 | +fi |
| 65 | + |
| 66 | +# Enter the temporary directory. |
| 67 | +if ! pushd "$tmpdir"; then |
| 68 | + printf "Can't enter temp directory '%s'\n" "$tmpdir" |
| 69 | + exit 1 |
| 70 | +fi |
| 71 | + |
| 72 | +# We can either fetch the source from the target repos by cloning them, |
| 73 | +# or simply by downloading an archive/tarball of the current 'master' branches. |
| 74 | +if [ "$fetch_source_by_cloning" = '1' ]; then |
| 75 | + # Clone folders with git. |
| 76 | + # The code above using curl and tar should work, but git diff doesn't seem to like it. |
| 77 | + { git clone "https://github.com/${github_org1}/${github_repo1}.git" "$repo_dir1" && \ |
| 78 | + git clone "https://github.com/${github_org2}/${github_repo2}.git" "$repo_dir2"; } || |
| 79 | + { printf "Unable to clone one or more of the target repositories.\n" && cleanup_error; } |
| 80 | + |
| 81 | + # Enter each cloned repo and delete the .git folder to eliminate a bunch of garbage in the patch. |
| 82 | + remove_git "$repo_dir1" |
| 83 | + remove_git "$repo_dir2" |
| 84 | +else |
| 85 | + # Download source tarballs for both repos. |
| 86 | + repo_archive1="$repo_dir1.zip" |
| 87 | + repo_archive2="$repo_dir2.zip" |
| 88 | + { curl -L -o "$repo_archive1" "https://github.com/${github_org1}/${github_repo1}/archive/master.zip" && \ |
| 89 | + curl -L -o "$repo_archive2" "https://github.com/${github_org2}/${github_repo2}/archive/master.zip"; } || \ |
| 90 | + { printf "Couldn't download one or more of the source tarballs.\n" && cleanup_error; } |
| 91 | + |
| 92 | + # Extract the contents of the source tarballs. |
| 93 | + { mkdir "$repo_dir1" && tar -xzf "$repo_archive1" -C "$repo_dir1" && \ |
| 94 | + mkdir "$repo_dir2" && tar -xzf "$repo_archive2" -C "$repo_dir2"; } || \ |
| 95 | + { printf "Couldn't extract one or more of the source tarballs.\n" && cleanup_error; } |
| 96 | +fi |
| 97 | + |
| 98 | +# Remove unwanted/"don't care" files from both repos. |
| 99 | +remove_irrelevant_files "$repo_dir1" |
| 100 | +remove_irrelevant_files "$repo_dir2" |
| 101 | + |
| 102 | +# Use git-diff to compare the two source trees and create a patch. |
| 103 | +# Note, the 'git diff' command reeturns with non-zero exit code if there are any warnings emitted, |
| 104 | +# which there will be -- so we can't really check the exit code to see if it succeeded' |
| 105 | +if [ "$include_all_changes" != '1' ]; then |
| 106 | + diff_filter_arg="--diff-filter=ad" |
| 107 | +fi |
| 108 | + |
| 109 | +git diff --diff-algorithm=minimal "$diff_filter_arg" --no-index -- "$repo_dir1" "$repo_dir2" > "$patch_path" |
| 110 | + |
| 111 | +# Cleanup the temp folder. |
| 112 | +cleanup |
0 commit comments