aboutsummaryrefslogtreecommitdiff
blob: 09d9321675ba1a94f1a3f3ce7d5ed1aa34c310e3 (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
#!/bin/sh
#
# A bit of hackery to update everything that is humanly possible
# that maybe related to an older version of python. This script can
# be run as many times as you like. It will log the results in
# /tmp/python-updater.log
#
# OLD_PY_VER      = old python version we are upgrading from
# NEW_PY_VER      = new python 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 (eg. ones that have python compiled
#                   statically) - FIXME
#
# 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.
#

NEW_PY_VER=$(python -V 2>&1 | sed 's:Python ::' | cut -d. -f1-2)

PKGS_EXCEPTIONS="dev-lang/python sys-apps/portage"
PKGS_MANUAL="app-office/gnumeric app-office/dia x11-libs/vte"
LOGFILE="/var/log/python-updater.log"

# portage variables
PKG_DBDIR=/var/db/pkg
PORTDIR=`portageq portdir`
PORTDIR_OVERLAYS=`portageq portdir_overlay`

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

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



for old in 2.4 2.3 2.2 2.1; do
	if [ "${old}" != "${NEW_PY_VER}" ]; then
		if [ -e /usr/bin/python${old} ] ; then
			OLD_PY_VER=${old}
			break;
		fi
	fi
done


if [ -z "${OLD_PY_VER}" ] ; then
    eerror "Can't determine any previous Python version(s)."
    exit 1
fi


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

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

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

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


usage() {
	echo "usage: python-updater [-h|-p|-o X.X|-n X.X]"
	echo " -h      help"
	echo " -p      pretend (don't do anything)"
	echo " -o X.X  set old python version to upgrade from [default: ${OLD_PY_VER}]"
	echo " -n X.X  set new python version to upgrade to [default: ${NEW_PY_VER}]"
}

#
# Sanity check
#

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	

if [ ! -f ${LOGFILE} ]; then
	if ! touch ${LOGFILE} 2>&1 > /dev/null; then
		ewarn "Logging disabled due to permissions"
		LOGFILE=/dev/null
	fi
elif [ ! -w ${LOGFILE} -o ! -L ${LOGFILE} ]; then
	ewarn "Logging disabled due to permissions"
	LOGFILE=/dev/null
fi

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

#
# Test where portage is, in python2.2 or somewhere else?
#
for py in /usr/bin/python /usr/bin/python${OLD_PY_VER} /usr/bin/python${NEW_PY_VER}; do
	if ${py} -c "import portage"; then
		PORTAGE_PYTHON=${py}
		break;
	fi
done

#
#
# Find all packages that have installed something in 
# /usr/lib/python${OLD_PY_VER}
#
#
OLD_MODULES_DIRS="/usr/lib/python${OLD_PY_VER} /usr/lib32/python${OLD_PY_VER} /usr/lib64/python${OLD_PY_VER}"
OLD_INCLUDE_DIR=/usr/include/python${OLD_PY_VER}

eloginfo "Starting Python Updater from ${OLD_PY_VER} to ${NEW_PY_VER} :"
eloginfo "Searching for packages with files in ${OLD_MODULES_DIRS} .."

# 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 OLD_MODULES_DIR in ${OLD_MODULES_DIRS}; do
        if fgrep "${OLD_MODULES_DIR}" ${content} > /dev/null; then
            PKGS_TO_REMERGE="${PKGS_TO_REMERGE} ${CATPKGVER}"
	    elogecho "Adding to list: ${CATPKGVER}"
	elif fgrep "${OLD_INCLUDE_DIR}" ${content} > /dev/null; then
            PKGS_TO_REMERGE="${PKGS_TO_REMERGE} ${CATPKGVER}"
        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_MISSING=""

MASKED_STRING="been masked"
MISSING_STRING="there are no masked or unmasked 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 "${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 .."

PKGS_OK_SORTED="$(${PORTAGE_PYTHON} ${PORTDIR}/dev-lang/python/files/depreorder-topsort.py ${PKGS_OK} | xargs)"

eloginfo "Preparing to merge these packages in this order:"
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_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_MISSING}" ]; then
      echo
      ewarn " Missing Packages:"
	  ewarn " -----------------"
      ewarn " These packages need to be updated because their versions do"
      ewarn " not exist in portage anymore."
      echo
      for x in ${OUTPUT_PKGS_MISSING}; do 
         echo "   ${x}"
      done
   fi
   if [ -n "${OUTPUT_PKGS_FAILED}" ]; then
      echo
      ewarn " Failed Packaged:"
	  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 "Python 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 "Python update completed successfully."
fi