summaryrefslogtreecommitdiff
blob: d12b841f3358b598f115f8271d16660571964f59 (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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!/bin/sh
#
# This script has been modified by kosmikus and is based on 
# python-updater by liquidx.
#
# It tries to update any package that provides a ghc library.
# This script can be run as many times as you like. It will log the 
# results in /var/log/ghc-updater.log
#
# NEW_GHC_VER     = new ghc version we are upgrading to
# PKGS_EXCEPTIONS = packages that should NOT be re-emerged for any reason
# PKGS_MANUAL     = packages that should be re-emerged even if they don't
#                   fit the criteria
#
# Runtime Variables:
# 
# PKGS_TO_REMERGE = list of packages we deem to need re-emerging
# PKGS_OK         = list of packages that should be merged without any problems
# PKGS_MISSING    = list of packages that are installed, but cannot be merged
#                   because they have been pruned from portage
# PKGS_MASKED     = list of packages that are installed, but masked.
#

shopt -s nullglob

# fix the PATH to include the dirs where portage installs ghc
PATH="/usr/bin:/opt/ghc/bin:${PATH}"

NEW_GHC_VER=$(ghc --version | sed 's:^.*version ::')
NEW_GHC_LIBDIR=$(ghc --print-libdir)

PKGS_EXCEPTIONS="dev-lang/ghc dev-lang/ghc-bin"
PKGS_MANUAL=""
LOGFILE="/var/log/ghc-updater.log"

# portage variables
PKG_DBDIR=/var/db/pkg

# moved the portageq checks into a function to make command
# line parsing immediate

setup_portdir() {
	PORTDIR=`portageq portdir`
	PORTDIR_OVERLAYS=`portageq portdir_overlay`
}

PRETEND=0
PKGS_TO_REMERGE=""
PKGS_COUNT_REMERGE=0
PORTAGE_PYTHON="/usr/bin/python"

usage() {
	echo "usage: ghc-updater [options]"
	echo " -h, -?, --help   help"
	echo " -p, --pretend    pretend (don't do anything)"
}

# 
#
# Command Line Parsing
#
#
while [ -n "$1" ]; do
	case "$1" in
		-h | -\? | --help)
			usage
			exit 0
			;;
		-p | --pretend)
			PRETEND=1
			;;
		*)
			usage
			echo "unrecognised option: $1"
			;;
	esac
	shift
done

# load the gentoo-style info macros, but hack to get around
# it thinking this is an rc script
EBUILD="1"
source /sbin/functions.sh

# misc helper functions
eloginfo() {
	einfo $*
	DATESTRING=`date +"%Y/%m/%d %H:%M:%S"`
	(echo "${DATESTRING} - ${*}" >> ${LOGFILE}) 2>/dev/null
}

elogecho() {
	echo -n "   "
	echo $*
	DATESTRING=`date +"%Y/%m/%d %H:%M:%S"`
	(echo "${DATESTRING} - ${*}" >> ${LOGFILE}) 2>/dev/null
}

elogerr() {
	eerror $*
	DATESTRING=`date +"%Y/%m/%d %H:%M:%S"`
	(echo "${DATESTRING} ! ${*}" >> ${LOGFILE}) 2>/dev/null
}

elog() {
	DATESTRING=`date +"%Y/%m/%d %H:%M:%S"`
	(echo "${DATESTRING} - ${*}" >> ${LOGFILE}) 2>/dev/null
}

#
# Sanity check
#

setup_portdir

find_in_portdir() {
	local f
	for f in ${PORTDIR} ${PORTDIR_OVERLAYS}; do
		if [[ -f "${f}/${1}" ]]; then
			echo "${f}/${1}"
			return 0
		fi
	done
	return 1
}

if [ -z "${PORTDIR}" ]; then
	eerror "Unable to proceed. Can not find PORTDIR. Make sure the command:"
	eerror " "
	eerror "  portageq portdir"
	eerror " "
	eerror "returns a value. If it doesn't, make sure you have updated to"
	eerror "latest portage version."
	eerror " "
	eerror "Report bugs to http://bugs.gentoo.org/"
	exit 1
fi

#
#
# Find all packages that have installed something in
# directories of the form
#   /usr/lib/ghc-<version>
# or similar.
#
#   /usr/lib/ghc-bin-<version>
# is included because an old ghc-bin ebuild was buggy and
# installed to a wrong dir.
#
OLD_PACKAGES_DIR=""
# Exclude new library dir and lib symlinks:
for d in /{usr,opt/ghc}/lib{,64}/ghc{,-bin}-*; do
    [[ "${d}" == ${NEW_GHC_LIBDIR} ]] || [[ -L ${d%/*} ]] || OLD_PACKAGES_DIR="${OLD_PACKAGES_DIR}${d} "
done

eloginfo "Starting GHC Updater to $(which ghc), version ${NEW_GHC_VER} :"
eloginfo "Searching for packages with files in the directories:"
eloginfo "${OLD_PACKAGES_DIR}"

# iterate thru all the installed package's contents
for content in `find ${PKG_DBDIR} -name CONTENTS`; do
    # extract the category, package name and package version
    CATPKGVER=$(echo ${content} | sed "s:${PKG_DBDIR}/\(.*\)/CONTENTS:\1:")
    
    # exclude packages that are an exception, like portage and python itself.
    exception=0
    for exp in ${PKGS_EXCEPTIONS}; do
    	if [ -n "$(echo ${CATPKGVER} | grep ${exp})" ]; then
			exception=1
			break;
		fi
    done
	
    if [ ${exception} = 1 ]; then
       continue;
    fi

    for d in ${OLD_PACKAGES_DIR}; do
        if fgrep "${d}/" ${content} > /dev/null; then
            PKGS_TO_REMERGE="${PKGS_TO_REMERGE} ${CATPKGVER}"
            elogecho "${CATPKGVER} has files in ${d}"
        fi
    done
done    

# now we have to do each emerge seperately because if an installed version
# does not have the corresponding ebuild in portage, then it will bail.

eloginfo "Calculating Upgrade Package List .."

PKGS_OK=""
PKGS_MASKED=""
PKGS_BLOCKED=""
PKGS_MISSING=""

MASKED_STRING="been masked"
BLOCKED_STRING="is blocking"
MISSING_STRING='there are no ebuilds to satisfy'

for pkg in ${PKGS_TO_REMERGE}; do
   emerge_output="$(emerge -p '>='$pkg 2>&1)"
   if $(echo "${emerge_output}" | grep "${MASKED_STRING}" > /dev/null); then
      PKGS_MASKED="${PKGS_MASKED} $pkg"
	  elogecho ">=$pkg is masked"
   elif $(echo "${emerge_output}" | grep "${BLOCKED_STRING}" > /dev/null); then
      PKGS_BLOCKED="${PKGS_BLOCKED} $pkg"
	  elogecho ">=$pkg is blocked"
   elif $(echo "${emerge_output}" | grep "${MISSING_STRING}" > /dev/null); then
      PKGS_MISSING="${PKGS_MISSING} $pkg"
	  elogecho ">=$pkg is missing from portage"
   else
      PKGS_OK="${PKGS_OK} $pkg"
	  PKGS_COUNT_REMERGE=$((PKGS_COUNT_REMERGE + 1))
   fi
done      

#
# Use my super dumb package reordering algorithm that works most of the time
#

eloginfo "Re-ordering packages to merge .."

DEPSORT=$(find_in_portdir "dev-lang/ghc/files/depsort.py")
if [[ -z ${DEPSORT} ]]; then
	eerror "Fatal error: File dev-lang/ghc/files/depsort.py in portage tree."
	exit 1
fi
PKGS_OK_SORTED="$(${PORTAGE_PYTHON} ${DEPSORT} ${PKGS_OK} | xargs)"

if [[ -n ${PRETEND} ]]; then
	eloginfo "These are the packages that would be merged, in order:"
else
	eloginfo "Preparing to merge these packages in this order:"
fi
for pkg in $PKGS_OK_SORTED; do
	elogecho ">=$pkg"
done

# we emerge each package seperately to ensure we know exactly which ones might
# cause an error, and then report it at the end

COUNT=1
PKGS_FAILED=""
if [ "${PRETEND}" != "1" ]; then
	for pkg in ${PKGS_OK_SORTED}; do
		eloginfo "Starting to merge ($COUNT/$PKGS_COUNT_REMERGE) $pkg .."
		if ! emerge --oneshot --nodeps '>='$pkg; then
			PKGS_FAILED="${PKGS_FAILED} $pkg"
			elogerr "Failed merging $pkg ($COUNT/$PKGS_COUNT_REMERGE)!"
		fi
		COUNT=$((COUNT+1))		
	done
fi

# final output stuff
OUTPUT_PKGS_MASKED=""
for pkg in ${PKGS_MASKED}; do OUTPUT_PKGS_MASKED="${OUTPUT_PKGS_MASKED} '>='$pkg"; done
OUTPUT_PKGS_BLOCKED=""
for pkg in ${PKGS_BLOCKED}; do OUTPUT_PKGS_BLOCKED="${OUTPUT_PKGS_BLOCKED} $pkg"; done
OUTPUT_PKGS_MISSING=""
for pkg in ${PKGS_MISSING}; do OUTPUT_PKGS_MISSING="${OUTPUT_PKGS_MISSING} $pkg"; done
OUTPUT_PKGS_FAILED=""
for pkg in ${PKGS_FAILED}; do OUTPUT_PKGS_FAILED="${OUTPUT_PKGS_FAILED} '>='$pkg"; done

if [ -n "${PKGS_FAILED}" -o -n "${PKGS_MISSING}" -o -n "${PKGS_MASKED}" ]; then
   echo
   ewarn "************************************************************"
   ewarn "* Packages that still need to be manually emerged :        *"
   ewarn "************************************************************"
   if [ -n "${OUTPUT_PKGS_MASKED}" ]; then
      echo
      ewarn " Masked Packages:"
	  ewarn " ----------------"
      ewarn " Unmask the following packages (at your own risk) and  "
      ewarn " emerge them using this command after removing the '-p'"
      ewarn " parameter."
      echo
      ewarn " emerge -p ${OUTPUT_PKGS_MASKED}"
      echo
   fi
   if [ -n "${OUTPUT_PKGS_BLOCKED}" ]; then
      echo
      ewarn " Blocked Packages:"
	  ewarn " -----------------"
      ewarn " These packages are currently blocked; they might not yet"
      ewarn " be compatible with the current ghc. You can run ghc-updater"
      ewarn " again at a later time."
      echo
      for x in ${OUTPUT_PKGS_BLOCKED}; do 
         echo "   ${x}"
      done
   fi
   if [ -n "${OUTPUT_PKGS_MISSING}" ]; then
      echo
      ewarn " Missing Packages:"
	  ewarn " -----------------"
      ewarn " These packages cannot be updated because they do not exist"
      ewarn " in portage anymore."
      echo
      for x in ${OUTPUT_PKGS_MISSING}; do 
         echo "   ${x}"
      done
   fi
   if [ -n "${OUTPUT_PKGS_FAILED}" ]; then
      echo
      ewarn " Failed Packages:"
	  ewarn " ----------------"
      ewarn " These packages have failed and need to be re-emerged again."
	  ewarn " Alternatively, try re-running this script again to see if it"
	  ewarn " can be fixed."
      echo
      ewarn " emerge -p ${OUTPUT_PKGS_FAILED}"
      echo
   fi
   
   elog "GHC update completed with errors."
   elog "Masked Packages:"
   for x in ${PKGS_MASKED}; do
   		elog $x
   done
   elog "Missing Packages:"
   for x in ${PKGS_MISSING}; do
   		elog $x
   done
   elog "Failed Packages:"
   for x in ${PKGS_FAILED}; do
   		elog $x
   done   
   elog "Update script completed."
else
   eloginfo "GHC update completed successfully."
fi