summarylogtreecommitdiffstats
path: root/updpkgsrcs.sh
blob: 8adf9774e9ef01e1cee148947327f1f97869d768 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env bash

# Return Submodule's Git Command
#
# $_extraArgs: extra args for git submodule update commandline
# $1: "init" or none
function echoGitCMDForSubModule {
    local -A subParent
    local gitCMDName='git '
    for path in "${!subCommit[@]}"; do
        configUrl="-c submodule.${subName[$path]}.url=\"\${srcdir}/${path//\//|}\" \\"
        moduleParent=$path
        while true; do
            moduleParent=${moduleParent%\/*}
            if [[ -f $gitRepo/$moduleParent/.gitmodules ]]; then
                subParent[$moduleParent]+="$configUrl"$'\n'$(printf %"${#gitCMDName}"s); break
            elif [[ $moduleParent == "${moduleParent%\/*}" ]]; then
                subParent[.]+="$configUrl"$'\n'$(printf %"${#gitCMDName}"s); break
            fi
        done
    done
    count=1 && for parent in "${!subParent[@]}"; do
        if [[ $1 == init ]]; then
            echo -e "${gitCMDName}-C '$gitRepo/$parent' submodule init && \\"
        fi
        echo -en "${gitCMDName}${subParent[$parent]}-c protocol.file.allow=always -C '$gitRepo/$parent' submodule update ${_extraArgs}"
        if [ "${#subParent[@]}" == "$count" ]; then echo; else echo " && \\"; fi
        ((count++))
    done
}

declare subModuleSourceTextStart="# Auto generated by '${0##*/}', do not edit."
declare subModuleSourceTextEnd='# End'

# Return Submodule's Source Text
function echoSourceTextForSubModule {
    sourceArrayName='source+=('
    subModuleSourceText+="${subModuleSourceTextStart}"$'\n'"${sourceArrayName}"
    count=1 && for path in "${!subCommit[@]}"; do
        if [[ $path =~ ^(src|pkg|PKGBUILD|.SRCINFO)$ ]]; then
            echo 'TODO: fix submodule that name as src,pkg,PKGBUILD or .SRCINFO.' && exit 1
        fi
        subModule="${path//\//|}::git+${subUrl[$path]}#commit=${subCommit[$path]}"
        if [ "${#subCommit[@]}" == "$count" ]; then
            subModuleSourceText+="'$subModule'"
        else
            subModuleSourceText+="'$subModule'"$'\n'$(printf %"${#sourceArrayName}"s)
        fi
        ((count++))
    done
    subModuleSourceText+=") ${subModuleSourceTextEnd}"
    echo "$subModuleSourceText"
}

# Update source array in PKGBUILD
#
# $1: [Path to PKGBUILD]
function updateBuildScriptForSubModule {
    if buildScriptFile=$(readlink -se "$1"); then
        buildScript=$(cat "$buildScriptFile" 2> /dev/null)
        SourceText="$(echoSourceTextForSubModule)"
        if [[ $buildScript != *$SourceText* ]]; then
            sourceTextForSed=$(echo "$SourceText"|sed -ze 's&\n&\\n&g' -e 's&|&\\|&g')
            sededbuildScript=$(echo "$buildScript" | sed -z "s|\n$subModuleSourceTextStart\nsource+=([^)]*) $subModuleSourceTextEnd\n|\n$sourceTextForSed|")

            if [ "$buildScript" == "$sededbuildScript" ]; then
                echo "$SourceText" >> "$buildScriptFile"
            else
                echo "$sededbuildScript" > "$buildScriptFile"
            fi

            # shellcheck disable=SC2181,SC2320
            if [[ $? != 0 ]]; then
                echo "Failed to update '$buildScriptFile'. The file has not been modified."
            else
                echo "The source of submodules in '$buildScriptFile' have been updated! Please update checksums, then do makepkg again."
            fi && exit 2
        else
            echo "No update for Submodules, continue..." && exit 0
        fi
    else
        echo "Failed to update '$buildScriptFile'. The file is not exist." && exit 1
    fi
}

function printUsage {
	cat <<-EOF
	Update source array of Git submodules in PKGBUILD

	Contain functions:
	"echoSourceTextForSubModule": Echo source array of given Git repository
	"echoGitCMDForSubModule": Echo Git command for PKGBUILD to change submodule's url
	    init: Whether to initialize the submodule, optional if you want to get the submodule of a submodule next time
	    force: Add '--force' parameter to command when update submodule
	"updateBuildScriptForSubModule [Path to PKGBUILD]": Update source array and replace it in PKGBUILD
	    [Path to PKGBUILD]: The PKGBUILD that expected to be modified

	example:
	    $ export _repo="[Path to Git repository]"
	    $ ${0##*/} echoSourceTextForSubModule
	    $ ${0##*/} echoGitCMDForSubModule init force
	    $ ${0##*/} updateBuildScriptForSubModule "[Path to PKGBUILD]"

	EOF
}

declare -A subUrl
declare -A subName
declare -A subPath
declare -A subCommit

# Update arrays about Submodule
function readGitModules {
    gitModules=$(git config -f "$gitRepo/.gitmodules" -l) || return 1

    # Submodule's Commit Array
    gitModulesStatus=$(git -C "$gitRepo" submodule status --recursive --cached) || return 1
    IFS=$'\n' && for line in $gitModulesStatus; do
        line=${line:1}; line=${line% (*)}
        path=${line#* }
        subCommit+=(["$path"]="${line% *}")
        if [[ -f $gitRepo/$path/.gitmodules ]]; then
            gitModules+=$'\n'$(git config -f "$gitRepo/$path/.gitmodules" -l | sed "s#.path=#.path=$path/#g") || return 1
        fi
    done && unset IFS

    # Submodule's Path Array
    IFS=$'\n' && for line in $gitModules; do
        name=${line#submodule.}; name=${name%.*=*}
        if [[ $line =~ .*.path=.* ]]; then
            subName+=(["${line#*.path=}"]="$name") # So we can get name by path
            subPath+=(["$name"]="${line#*.path=}")
        fi
    done && unset IFS

    # Submodule's Url Array
    IFS=$'\n' && for line in $gitModules; do
        name=${line#submodule.}; name=${name%.*=*}
        if [[ $line =~ .*.url=.* ]]; then
            subUrl+=(["${subPath[$name]}"]="${line#*.url=}")
        fi
    done && unset IFS

    # Only support 'path' and 'url'
}

if ! type git > /dev/null 2>&1; then
    echo "This script needs \`git\` in order to work, aborting..." && exit 1
fi

gitRepo=${_repo:-$PWD}
if ! readGitModules; then
    printUsage; echo "No submodule in '$gitRepo', aborting..."; exit 1
fi

case "$1" in
    ForSource)
        ;;
    echoGitCMDForSubModule)
        for arg in "${@:2}"; do
            case "$arg" in
                '')
                    ;;
                force)
                    _extraArgs='--force'
                    ;;
                init)
                    _Args='init'
                    ;;
                *)
                    printUsage && exit 1
                    ;;
            esac
        done
        echoGitCMDForSubModule "$_Args"
        ;;
    echoSourceTextForSubModule)
        echoSourceTextForSubModule
        ;;
    updateBuildScriptForSubModule)
        updateBuildScriptForSubModule "${2:-$gitRepo/../../PKGBUILD}" # The path to PKGBUILD in most case
        ;;
    *)
        printUsage && exit 1
        ;;
esac