3 # Creates and upload a git module tarball
6 # This script is intended to run on any platform supported by X.Org.
7 # Basically, it should be able to run in a Bourne shell.
13 #------------------------------------------------------------------------------
14 # Function: check_local_changes
15 #------------------------------------------------------------------------------
17 check_local_changes
() {
18 git
diff --quiet HEAD
> /dev
/null
2>&1
21 echo "Uncommitted changes found. Did you forget to commit? Aborting."
23 echo "You can perform a 'git stash' to save your local changes and"
24 echo "a 'git stash apply' to recover them after the tarball release."
25 echo "Make sure to rebuild and run 'make distcheck' again."
27 echo "Alternatively, you can clone the module in another directory"
28 echo "and run ./configure. No need to build if testing was finished."
35 #------------------------------------------------------------------------------
36 # Function: check_option_args
37 #------------------------------------------------------------------------------
39 # perform sanity checks on cmdline args which require arguments
41 # $1 - the option being examined
42 # $2 - the argument to the option
44 # if it returns, everything is good
50 # check for an argument
51 if [ x
"$arg" = x
]; then
53 echo "Error: the '$option' option is missing its required argument."
59 # does the argument look like an option?
60 echo $arg |
$GREP "^-" > /dev
/null
63 echo "Error: the argument '$arg' of option '$option' looks like an option itself."
70 #------------------------------------------------------------------------------
71 # Function: check_modules_specification
72 #------------------------------------------------------------------------------
74 check_modules_specification
() {
76 if [ x
"$MODFILE" = x
]; then
77 if [ x
"${INPUT_MODULES}" = x
]; then
79 echo "Error: no modules specified (blank command line)."
87 #------------------------------------------------------------------------------
88 # Function: generate_announce
89 #------------------------------------------------------------------------------
94 Subject: [ANNOUNCE] $pkg_name $pkg_version
98 `git log --no-merges "$tag_range" | git shortlog`
104 for tarball
in $tarbz2 $targz $tarxz; do
106 http://$host_current/$section_path/$tarball
107 MD5: `$MD5SUM $tarball`
108 SHA1: `$SHA1SUM $tarball`
109 SHA256: `$SHA256SUM $tarball`
115 #------------------------------------------------------------------------------
116 # Function: read_modfile
117 #------------------------------------------------------------------------------
119 # Read the module names from the file and set a variable to hold them
120 # This will be the same interface as cmd line supplied modules
124 if [ x
"$MODFILE" != x
]; then
125 # Make sure the file is sane
126 if [ ! -r "$MODFILE" ]; then
127 echo "Error: module file '$MODFILE' is not readable or does not exist."
130 # read from input file, skipping blank and comment lines
133 if [ x
"$line" = x
]; then
137 if echo "$line" |
$GREP -q "^#" ; then
140 INPUT_MODULES
="$INPUT_MODULES $line"
146 #------------------------------------------------------------------------------
147 # Function: print_epilog
148 #------------------------------------------------------------------------------
152 epilog
="======== Successful Completion"
153 if [ x
"$NO_QUIT" != x
]; then
154 if [ x
"$failed_modules" != x
]; then
155 epilog
="======== Partial Completion"
157 elif [ x
"$failed_modules" != x
]; then
158 epilog
="======== Stopped on Error"
162 echo "$epilog `date`"
164 # Report about modules that failed for one reason or another
165 if [ x
"$failed_modules" != x
]; then
166 echo " List of failed modules:"
167 for mod
in $failed_modules; do
175 #------------------------------------------------------------------------------
176 # Function: process_modules
177 #------------------------------------------------------------------------------
179 # Loop through each module to release
180 # Exit on error if --no-quit was not specified
183 for MODULE_RPATH
in ${INPUT_MODULES}; do
184 if ! process_module
; then
185 echo "Error: processing module \"$MODULE_RPATH\" failed."
186 failed_modules
="$failed_modules $MODULE_RPATH"
187 if [ x
"$NO_QUIT" = x
]; then
195 #------------------------------------------------------------------------------
196 # Function: get_section
197 #------------------------------------------------------------------------------
198 # Code 'return 0' on success
199 # Code 'return 1' on error
200 # Sets global variable $section
203 local full_module_url
205 # Obtain the git url in order to find the section to which this module belongs
206 full_module_url
=`git config --get remote.$remote_name.url | sed 's:\.git$::'`
207 if [ $?
-ne 0 ]; then
208 echo "Error: unable to obtain git url for remote \"$remote_name\"."
212 # The last part of the git url will tell us the section. Look for xorg first
213 echo "$full_module_url"
214 module_url
=`echo "$full_module_url" | $GREP -o "/xorg/.*"`
215 if [ $?
-eq 0 ]; then
216 module_url
=`echo $module_url | cut -d'/' -f3,4`
218 # The look for mesa, xcb, etc...
219 module_url
=`echo "$full_module_url" | $GREP -o -e "/mesa/.*" -e "/xcb/.*" -e "/xkeyboard-config" -e "/nouveau/xf86-video-nouveau" -e "/libevdev"`
220 if [ $?
-eq 0 ]; then
221 module_url
=`echo $module_url | cut -d'/' -f2,3`
223 echo "Error: unable to locate a valid project url from \"$full_module_url\"."
224 echo "Cannot establish url as one of xorg, mesa, xcb, xf86-video-nouveau or xkeyboard-config."
229 # Find the section (subdirs) where the tarballs are to be uploaded
230 # The module relative path can be app/xfs, xserver, or mesa/drm for example
231 section
=`echo $module_url | cut -d'/' -f1`
232 if [ $?
-ne 0 ]; then
233 echo "Error: unable to extract section from $module_url first field."
237 if [ x
"$section" = xmesa
]; then
238 section
=`echo $module_url | cut -d'/' -f2`
239 if [ $?
-ne 0 ]; then
240 echo "Error: unable to extract section from $module_url second field."
242 elif [ x
"$section" != xdrm
]; then
243 echo "Error: section $section is not supported, only libdrm is."
252 #------------------------------------------------------------------------------
253 # Function: process_module
254 #------------------------------------------------------------------------------
255 # Code 'return 0' on success to process the next module
256 # Code 'return 1' on error to process next module if invoked with --no-quit
262 echo "======== Processing \"$top_src/$MODULE_RPATH\""
264 # This is the location where the script has been invoked
265 if [ ! -d $MODULE_RPATH ] ; then
266 echo "Error: $MODULE_RPATH cannot be found under $top_src."
270 # Change directory to be in the git module
272 if [ $?
-ne 0 ]; then
273 echo "Error: failed to cd to $MODULE_RPATH."
277 # ----- Now in the git module *root* directory ----- #
279 # Check that this is indeed a git module
280 if [ ! -d .git
]; then
281 echo "Error: there is no git module here: `pwd`"
285 # Change directory to be in the git build directory (could be out-of-source)
286 # More than one can be found when distcheck has run and failed
287 configNum
=`find . -name config.status -type f | wc -l | sed 's:^ *::'`
288 if [ $?
-ne 0 ]; then
289 echo "Error: failed to locate config.status."
290 echo "Has the module been configured?"
293 if [ x
"$configNum" = x0
]; then
294 echo "Error: failed to locate config.status, has the module been configured?"
297 if [ x
"$configNum" != x1
]; then
298 echo "Error: more than one config.status file was found,"
299 echo " clean-up previously failed attempts at distcheck"
302 status_file
=`find . -name config.status -type f`
303 if [ $?
-ne 0 ]; then
304 echo "Error: failed to locate config.status."
305 echo "Has the module been configured?"
308 build_dir
=`dirname $status_file`
310 if [ $?
-ne 0 ]; then
311 echo "Error: failed to cd to $MODULE_RPATH/$build_dir."
316 # ----- Now in the git module *build* directory ----- #
318 # Check for uncommitted/queued changes.
320 if [ $?
-ne 0 ]; then
325 # Determine what is the current branch and the remote name
326 current_branch
=`git branch | $GREP "\*" | sed -e "s/\* //"`
327 remote_name
=`git config --get branch.$current_branch.remote`
328 remote_branch
=`git config --get branch.$current_branch.merge | cut -d'/' -f3,4`
329 echo "Info: working off the \"$current_branch\" branch tracking the remote \"$remote_name/$remote_branch\"."
333 if [ $?
-ne 0 ]; then
338 # Run 'make dist/distcheck' to ensure the tarball matches the git module content
339 # Important to run make dist/distcheck before looking in Makefile, may need to reconfigure
340 echo "Info: running \"make $MAKE_DIST_CMD\" to create tarballs:"
341 ${MAKE} $MAKEFLAGS $MAKE_DIST_CMD > /dev
/null
342 if [ $?
-ne 0 ]; then
343 echo "Error: \"$MAKE $MAKEFLAGS $MAKE_DIST_CMD\" failed."
348 # Find out the tarname from the makefile
349 pkg_name
=`$GREP '^PACKAGE = ' Makefile | sed 's|PACKAGE = ||'`
350 pkg_version
=`$GREP '^VERSION = ' Makefile | sed 's|VERSION = ||'`
351 tar_name
="$pkg_name-$pkg_version"
353 targz
=$tar_name.
tar.gz
354 tarbz2
=$tar_name.
tar.bz2
355 tarxz
=$tar_name.
tar.xz
357 [ -e $targz ] && ls -l $targz ||
unset targz
358 [ -e $tarbz2 ] && ls -l $tarbz2 ||
unset tarbz2
359 [ -e $tarxz ] && ls -l $tarxz ||
unset tarxz
361 if [ -z "$targz" -a -z "$tarbz2" -a -z "$tarxz" ]; then
362 echo "Error: no compatible tarballs found."
367 # Obtain the top commit SHA which should be the version bump
368 # It should not have been tagged yet (the script will do it later)
369 local_top_commit_sha
=`git rev-list --max-count=1 HEAD`
370 if [ $?
-ne 0 ]; then
371 echo "Error: unable to obtain the local top commit id."
376 # Check that the top commit looks like a version bump
377 git
diff --unified=0 HEAD^ |
$GREP -F $pkg_version >/dev
/null
2>&1
378 if [ $?
-ne 0 ]; then
379 echo "Error: the local top commit does not look like a version bump."
380 echo " the diff does not contain the string \"$pkg_version\"."
381 local_top_commit_descr
=`git log --oneline --max-count=1 $local_top_commit_sha`
382 echo " the local top commit is: \"$local_top_commit_descr\""
387 # Check that the top commit has been pushed to remote
388 remote_top_commit_sha
=`git rev-list --max-count=1 $remote_name/$remote_branch`
389 if [ $?
-ne 0 ]; then
390 echo "Error: unable to obtain top commit from the remote repository."
394 if [ x
"$remote_top_commit_sha" != x
"$local_top_commit_sha" ]; then
395 echo "Error: the local top commit has not been pushed to the remote."
396 local_top_commit_descr
=`git log --oneline --max-count=1 $local_top_commit_sha`
397 echo " the local top commit is: \"$local_top_commit_descr\""
402 # If a tag exists with the the tar name, ensure it is tagging the top commit
403 # It may happen if the version set in configure.ac has been previously released
404 tagged_commit_sha
=`git rev-list --max-count=1 $tag_name 2>/dev/null`
405 if [ $?
-eq 0 ]; then
406 # Check if the tag is pointing to the top commit
407 if [ x
"$tagged_commit_sha" != x
"$remote_top_commit_sha" ]; then
408 echo "Error: the \"$tag_name\" already exists."
409 echo " this tag is not tagging the top commit."
410 remote_top_commit_descr
=`git log --oneline --max-count=1 $remote_top_commit_sha`
411 echo " the top commit is: \"$remote_top_commit_descr\""
412 local_tag_commit_descr
=`git log --oneline --max-count=1 $tagged_commit_sha`
413 echo " tag \"$tag_name\" is tagging some other commit: \"$local_tag_commit_descr\""
417 echo "Info: module already tagged with \"$tag_name\"."
420 # Tag the top commit with the tar name
421 if [ x
"$DRY_RUN" = x
]; then
422 git tag
-m $tag_name $tag_name
423 if [ $?
-ne 0 ]; then
424 echo "Error: unable to tag module with \"$tag_name\"."
428 echo "Info: module tagged with \"$tag_name\"."
431 echo "Info: skipping the commit tagging in dry-run mode."
435 # --------- Now the tarballs are ready to upload ----------
437 # The hostname which is used to connect to the development resources
438 hostname
="annarchy.freedesktop.org"
440 # Some hostnames are also used as /srv subdirs
441 host_fdo
="www.freedesktop.org"
442 host_xorg
="xorg.freedesktop.org"
443 host_dri
="dri.freedesktop.org"
445 # Mailing lists where to post the all [Announce] e-mails
446 list_to
="xorg-announce@lists.freedesktop.org"
448 # Mailing lists to be CC according to the project (xorg|dri|xkb)
449 list_xorg_user
="xorg@lists.freedesktop.org"
450 list_dri_devel
="dri-devel@lists.freedesktop.org"
451 list_xkb
="xkb@listserv.bat.ru"
452 list_xcb
="xcb@lists.freedesktop.org"
453 list_nouveau
="nouveau@lists.freedesktop.org"
455 # nouveau is very special.. sigh
456 if [ x
"$section" = xnouveau
]; then
458 list_cc
=$list_nouveau
460 list_cc
=$list_xorg_user
463 host_current
=$host_xorg
464 section_path
=archive
/individual
/$section
465 srv_path
="/srv/$host_current/$section_path"
467 # Handle special cases such as non xorg projects or migrated xorg projects
468 # Xcb has a separate mailing list
469 if [ x
"$section" = xxcb
]; then
473 # Module mesa/drm goes in the dri "libdrm" section
474 if [ x
"$section" = xdrm
]; then
475 host_current
=$host_dri
477 srv_path
="/srv/$host_current/www/$section_path"
478 list_cc
=$list_dri_devel
481 # Module xkeyboard-config goes in a subdir of the xorg "data" section
482 if [ x
"$section" = xxkeyboard-config
]; then
483 host_current
=$host_xorg
484 section_path
=archive
/individual
/data
/$section
485 srv_path
="/srv/$host_current/$section_path"
489 if [ x
"$section" = xlibevdev
]; then
490 host_current
=$host_fdo
491 section_path
="software/$section"
492 srv_path
="/srv/$host_current/www/$section_path"
493 list_to
=input-tools@lists.freedesktop.org
497 # Use personal web space on the host for unit testing (leave commented out)
498 # srv_path="~/public_html$srv_path"
500 # Check that the server path actually does exist
501 ssh $USER_NAME$hostname ls $srv_path >/dev
/null
2>&1 ||
502 if [ $?
-ne 0 ]; then
503 echo "Error: the path \"$srv_path\" on the web server does not exist."
508 # Check for already existing tarballs
509 for tarball
in $targz $tarbz2 $tarxz; do
510 ssh $USER_NAME$hostname ls $srv_path/$tarball >/dev
/null
2>&1
511 if [ $?
-eq 0 ]; then
512 if [ "x$FORCE" = "xyes" ]; then
513 echo "Warning: overwriting released tarballs due to --force option."
515 echo "Error: tarball $tar_name already exists. Use --force to overwrite."
522 # Upload to host using the 'scp' remote file copy program
523 if [ x
"$DRY_RUN" = x
]; then
524 echo "Info: uploading tarballs to web server:"
525 scp
$targz $tarbz2 $tarxz $USER_NAME$hostname:$srv_path
526 if [ $?
-ne 0 ]; then
527 echo "Error: the tarballs uploading failed."
532 echo "Info: skipping tarballs uploading in dry-run mode."
533 echo " \"$srv_path\"."
536 # Pushing the top commit tag to the remote repository
537 if [ x
$DRY_RUN = x
]; then
538 echo "Info: pushing tag \"$tar_name\" to remote \"$remote_name\":"
539 git push
$remote_name $tar_name
540 if [ $?
-ne 0 ]; then
541 echo "Error: unable to push tag \"$tar_name\" to the remote repository."
542 echo " it is recommended you fix this manually and not run the script again"
547 echo "Info: skipped pushing tag \"$tar_name\" to the remote repository in dry-run mode."
550 MD5SUM
=`which md5sum || which gmd5sum`
551 SHA1SUM
=`which sha1sum || which gsha1sum`
552 SHA256SUM
=`which sha256sum || which gsha256sum`
554 # --------- Generate the announce e-mail ------------------
555 # Failing to generate the announce is not considered a fatal error
557 # Git-describe returns only "the most recent tag", it may not be the expected one
558 # However, we only use it for the commit history which will be the same anyway.
559 tag_previous
=`git describe --abbrev=0 HEAD^ 2>/dev/null`
560 # Git fails with rc=128 if no tags can be found prior to HEAD^
561 if [ $?
-ne 0 ]; then
562 if [ $?
-ne 0 ]; then
563 echo "Warning: unable to find a previous tag."
564 echo " perhaps a first release on this branch."
565 echo " Please check the commit history in the announce."
568 if [ x
"$tag_previous" != x
]; then
569 # The top commit may not have been tagged in dry-run mode. Use commit.
570 tag_range
=$tag_previous..
$local_top_commit_sha
574 generate_announce
> "$tar_name.announce"
575 echo "Info: [ANNOUNCE] template generated in \"$tar_name.announce\" file."
576 echo " Please pgp sign and send it."
578 # --------- Update the JH Build moduleset -----------------
579 # Failing to update the jh moduleset is not considered a fatal error
580 if [ x
"$JH_MODULESET" != x
]; then
581 for tarball
in $targz $tarbz2 $tarxz; do
582 if [ x
$DRY_RUN = x
]; then
583 sha1sum=`$SHA1SUM $tarball | cut -d' ' -f1`
584 $top_src/util
/modular
/update-moduleset.sh
$JH_MODULESET $sha1sum $tarball
585 echo "Info: updated jh moduleset: \"$JH_MODULESET\""
587 echo "Info: skipping jh moduleset \"$JH_MODULESET\" update in dry-run mode."
590 # $tar* may be unset, so simply loop through all of them and the
591 # first one that is set updates the module file
597 # --------- Successful completion --------------------------
603 #------------------------------------------------------------------------------
605 #------------------------------------------------------------------------------
606 # Displays the script usage and exits successfully
609 basename="`expr "//$0" : '.*/\([^/]*\)'`"
612 Usage: $basename [options] path...
614 Where "path" is a relative path to a git module, including '.'.
617 --dist make 'dist' instead of 'distcheck'; use with caution
618 --distcheck Default, ignored for compatibility
619 --dry-run Does everything except tagging and uploading tarballs
620 --force Force overwriting an existing release
621 --help Display this help and exit successfully
622 --modfile <file> Release the git modules specified in <file>
623 --moduleset <file> The jhbuild moduleset full pathname to be updated
624 --no-quit Do not quit after error; just print error message
625 --user <name>@ Username of your fdo account if not configured in ssh
627 Environment variables defined by the "make" program and used by release.sh:
628 MAKE The name of the make command [make]
629 MAKEFLAGS: Options to pass to all \$(MAKE) invocations
634 #------------------------------------------------------------------------------
636 #------------------------------------------------------------------------------
639 # Choose which make program to use (could be gmake)
642 # Choose which grep program to use (on Solaris, must be gnu grep)
643 if [ "x$GREP" = "x" ] ; then
644 if [ -x /usr
/gnu
/bin
/grep ] ; then
645 GREP
=/usr
/gnu
/bin
/grep
652 # Set the default make tarball creation command
653 MAKE_DIST_CMD
=distcheck
655 # Process command line args
659 # Use 'dist' rather than 'distcheck' to create tarballs
660 # You really only want to do this if you're releasing a module you can't
661 # possibly build-test. Please consider carefully the wisdom of doing so.
665 # Use 'distcheck' to create tarballs
667 MAKE_DIST_CMD
=distcheck
669 # Does everything except uploading tarball
673 # Force overwriting an existing release
674 # Use only if nothing changed in the git repo
678 # Display this help and exit successfully
683 # Release the git modules specified in <file>
685 check_option_args
$1 $2
689 # The jhbuild moduleset to update with relase info
691 check_option_args
$1 $2
695 # Do not quit after error; just print error message
699 # Username of your fdo account if not configured in ssh
701 check_option_args
$1 $2
707 echo "Error: unknown option: $1"
714 echo "Error: unknown option: $1"
720 if [ x
"${MODFILE}" != x
]; then
722 echo "Error: specifying both modules and --modfile is not permitted"
727 INPUT_MODULES
="${INPUT_MODULES} $1"
734 # If no modules specified (blank cmd line) display help
735 check_modules_specification
737 # Read the module file and normalize input in INPUT_MODULES
740 # Loop through each module to release
741 # Exit on error if --no-quit no specified
744 # Print the epilog with final status