@@ -18,25 +18,31 @@ set -e # Work even if somebody does "sh thisscript.sh".
1818XDG_DATA_HOME=${XDG_DATA_HOME:- ~/ .local/ share}
1919VENV_NAME=" letsencrypt"
2020VENV_PATH=${VENV_PATH:- " $XDG_DATA_HOME /$VENV_NAME " }
21- VENV_BIN=${ VENV_PATH} /bin
22- LE_AUTO_VERSION=" 0.4.0 "
21+ VENV_BIN=" $ VENV_PATH /bin"
22+ LE_AUTO_VERSION=" 0.4.1 "
2323
2424# This script takes the same arguments as the main letsencrypt program, but it
2525# additionally responds to --verbose (more output) and --debug (allow support
2626# for experimental platforms)
2727for arg in " $@ " ; do
28- # This first clause is redundant with the third, but hedging on portability
29- if [ " $arg " = " -v" ] || [ " $arg " = " --verbose" ] || echo " $arg " | grep -E -- " -v+$" ; then
30- VERBOSE=1
31- elif [ " $arg " = " --no-self-upgrade" ] ; then
32- # Do not upgrade this script (also prevents client upgrades, because each
33- # copy of the script pins a hash of the python client)
34- NO_SELF_UPGRADE=1
35- elif [ " $arg " = " --os-packages-only" ] ; then
36- OS_PACKAGES_ONLY=1
37- elif [ " $arg " = " --debug" ]; then
38- DEBUG=1
39- fi
28+ case " $arg " in
29+ --debug)
30+ DEBUG=1;;
31+ --os-packages-only)
32+ OS_PACKAGES_ONLY=1;;
33+ --no-self-upgrade)
34+ # Do not upgrade this script (also prevents client upgrades, because each
35+ # copy of the script pins a hash of the python client)
36+ NO_SELF_UPGRADE=1;;
37+ --verbose)
38+ VERBOSE=1;;
39+ [!-]* |-* [!v]* |-)
40+ # Anything that isn't -v, -vv, etc.: that is, anything that does not
41+ # start with a -, contains anything that's not a v, or is just "-"
42+ ;;
43+ * ) # -v+ remains.
44+ VERBOSE=1;;
45+ esac
4046done
4147
4248# letsencrypt-auto needs root access to bootstrap OS dependencies, and
@@ -91,21 +97,18 @@ ExperimentalBootstrap() {
9197}
9298
9399DeterminePythonVersion () {
94- if command -v python2.7 > /dev/null ; then
95- export LE_PYTHON=${LE_PYTHON:- python2.7}
96- elif command -v python27 > /dev/null ; then
97- export LE_PYTHON=${LE_PYTHON:- python27}
98- elif command -v python2 > /dev/null ; then
99- export LE_PYTHON=${LE_PYTHON:- python2}
100- elif command -v python > /dev/null ; then
101- export LE_PYTHON=${LE_PYTHON:- python}
102- else
103- echo " Cannot find any Pythons... please install one!"
100+ for LE_PYTHON in " $LE_PYTHON " python2.7 python27 python2 python; do
101+ # Break (while keeping the LE_PYTHON value) if found.
102+ command -v " $LE_PYTHON " > /dev/null && break
103+ done
104+ if [ " $? " != " 0" ]; then
105+ echo " Cannot find any Pythons; please install one!"
104106 exit 1
105107 fi
108+ export LE_PYTHON
106109
107- PYVER=` " $LE_PYTHON " --version 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed ' s/\.//' `
108- if [ $PYVER -lt 26 ]; then
110+ PYVER=` " $LE_PYTHON " -V 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed ' s/\.//' `
111+ if [ " $PYVER " -lt 26 ]; then
109112 echo " You have an ancient version of Python entombed in your operating system..."
110113 echo " This isn't going to work; you'll need at least version 2.6."
111114 exit 1
@@ -165,7 +168,7 @@ BootstrapDebCommon() {
165168 /bin/echo ' (Backports are only installed if explicitly requested via "apt-get install -t wheezy-backports")'
166169 fi
167170
168- sudo sh -c " echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME .list"
171+ $SUDO sh -c " echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME .list"
169172 $SUDO apt-get update
170173 fi
171174 fi
@@ -304,10 +307,11 @@ BootstrapArchCommon() {
304307 pkg-config
305308 "
306309
307- missing=$( " $SUDO " pacman -T $deps )
310+ # pacman -T exits with 127 if there are missing dependencies
311+ missing=$( $SUDO pacman -T $deps ) || true
308312
309313 if [ " $missing " ]; then
310- " $SUDO " pacman -S --needed $missing
314+ $SUDO pacman -S --needed $missing
311315 fi
312316}
313317
@@ -324,19 +328,19 @@ BootstrapGentooCommon() {
324328
325329 case " $PACKAGE_MANAGER " in
326330 (paludis)
327- " $SUDO " cave resolve --keep-targets if-possible $PACKAGES -x
331+ $SUDO cave resolve --preserve-world --keep-targets if-possible $PACKAGES -x
328332 ;;
329333 (pkgcore)
330- " $SUDO " pmerge --noreplace $PACKAGES
334+ $SUDO pmerge --noreplace --oneshot $PACKAGES
331335 ;;
332336 (portage|* )
333- " $SUDO " emerge --noreplace $PACKAGES
337+ $SUDO emerge --noreplace --oneshot $PACKAGES
334338 ;;
335339 esac
336340}
337341
338342BootstrapFreeBsd () {
339- " $SUDO " pkg install -Ay \
343+ $SUDO pkg install -Ay \
340344 python \
341345 py27-virtualenv \
342346 augeas \
@@ -345,20 +349,27 @@ BootstrapFreeBsd() {
345349
346350BootstrapMac () {
347351 if ! hash brew 2> /dev/null; then
348- echo " Homebrew Not Installed \nDownloading..."
352+ echo " Homebrew not installed. \nDownloading..."
349353 ruby -e " $( curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install) "
350354 fi
351355
352- brew install augeas
353- brew install dialog
356+ if [ -z " $( brew list --versions augeas) " ]; then
357+ echo " augeas not installed.\nInstalling augeas from Homebrew..."
358+ brew install augeas
359+ fi
354360
355- if ! hash pip 2> /dev/null; then
356- echo " pip Not Installed\nInstalling python from Homebrew..."
361+ if [ -z " $( brew list --versions dialog) " ]; then
362+ echo " dialog not installed.\nInstalling dialog from Homebrew..."
363+ brew install dialog
364+ fi
365+
366+ if [ -z " $( brew list --versions python) " ]; then
367+ echo " python not installed.\nInstalling python from Homebrew..."
357368 brew install python
358369 fi
359370
360371 if ! hash virtualenv 2> /dev/null; then
361- echo " virtualenv Not Installed \nInstalling with pip"
372+ echo " virtualenv not installed. \nInstalling with pip... "
362373 pip install virtualenv
363374 fi
364375}
@@ -412,9 +423,10 @@ TempDir() {
412423
413424
414425
415- if [ " $NO_SELF_UPGRADE " = 1 ]; then
426+ if [ " $1 " = " --le-auto-phase2 " ]; then
416427 # Phase 2: Create venv, install LE, and run.
417428
429+ shift 1 # the --le-auto-phase2 arg
418430 if [ -f " $VENV_BIN /letsencrypt" ]; then
419431 INSTALLED_VERSION=$( " $VENV_BIN /letsencrypt" --version 2>&1 | cut -d " " -f 2)
420432 else
@@ -609,10 +621,6 @@ traceback2==1.4.0
609621# sha256: IogqDkGMKE4fcYqCKzsCKUTVPS2QjhaQsxmp0-ssBXk
610622unittest2==1.1.0
611623
612- # sha256: aUkbUwUVfDxuDwSnAZhNaud_1yn8HJrNJQd_HfOFMms
613- # sha256: 619wCpv8lkILBVY1r5AC02YuQ9gMP_0x8iTCW8DV9GI
614- Werkzeug==0.11.3
615-
616624# sha256: KCwRK1XdjjyGmjVx-GdnwVCrEoSprOK97CJsWSrK-Bo
617625zope.component==4.2.2
618626
@@ -638,22 +646,25 @@ zope.event==4.1.0
638646# sha256: sJyMHUezUxxADgGVaX8UFKYyId5u9HhZik8UYPfZo5I
639647zope.interface==4.1.3
640648
641- # sha256: ilvjjTWOS86xchl0WBZ0YOAw_0rmqdnjNsxb1hq2RD8
642- # sha256: T37KMj0TnsuvHIzCCmoww2fpfpOBTj7cd4NAqucXcpw
643- acme==0.4.0
644-
645- # sha256: 33BQiANlNLGqGpirTfdCEElTF9YbpaKiYpTbK4zeGD8
646- # sha256: lwsV1OdEzzlMeb08C_PRxaCXZ2vOk_1AI2755rZHmPM
647- letsencrypt==0.4.0
648-
649- # sha256: D3YDaVFjLsMSEfjI5B5D5tn5FeWUtNHYXCObw3ih2tg
650- # sha256: VTgvsePYGRmI4IOSAnxoYFHd8KciD73bxIuIHtbVFd8
651- letsencrypt-apache==0.4.0
652-
653649# sha256: uDndLZwRfHAUMMFJlWkYpCOphjtIsJyQ4wpgE-fS9E8
654650# sha256: j4MIDaoknQNsvM-4rlzG_wB7iNbZN1ITca-r57Gbrbw
655651mock==1.0.1
656652
653+ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT;
654+ # ADD ALL DEPENDENCIES ABOVE
655+
656+ # sha256: zd_qpRKPaFs00y5hex5Rbu5CVLWzed7pBGL28juxoHM
657+ # sha256: 18Gfo85AbZXE46GyTkyePthTNiUeoGTQNcXlSvmRQvM
658+ acme==0.4.1
659+
660+ # sha256: wIuGh8yh1TeOClXW0qLz70bKeM9Ax4bfFNrkKSDjbbo
661+ # sha256: 7TeAUt8cZ0IZQuQNuUm8MoH8vPWlKaCrwWAkdCEs_5s
662+ letsencrypt==0.4.1
663+
664+ # sha256: bnpKXJTXy9cFSktJLtvTCTovJJybc__Ivqs6XaXxk9U
665+ # sha256: bcvJ6j5UB8sOJ_M88DAsqvmaLxD2UnAP9ys-_J6Bdcc
666+ letsencrypt-apache==0.4.1
667+
657668UNLIKELY_EOF
658669 # -------------------------------------------------------------------------
659670 cat << "UNLIKELY_EOF " > "$TEMP_DIR/peep.py"
@@ -745,6 +756,7 @@ except ImportError:
745756 from pip.util import url_to_path # 0.7.0
746757 except ImportError:
747758 from pip.util import url_to_filename as url_to_path # 0.6.2
759+ from pip.exceptions import InstallationError
748760from pip.index import PackageFinder, Link
749761try:
750762 from pip.log import logger
@@ -763,7 +775,7 @@ except ImportError:
763775
764776 DownloadProgressBar = DownloadProgressSpinner = NullProgressBar
765777
766- __version__ = 3, 0, 0
778+ __version__ = 3, 1, 1
767779
768780try:
769781 from pip.index import FormatControl # noqa
@@ -781,6 +793,7 @@ ITS_FINE_ITS_FINE = 0
781793SOMETHING_WENT_WRONG = 1
782794# "Traditional" for command-line errors according to optparse docs:
783795COMMAND_LINE_ERROR = 2
796+ UNHANDLED_EXCEPTION = 3
784797
785798ARCHIVE_EXTENSIONS = ('.tar.bz2', '.tar.gz', '.tgz', '.tar', '.zip')
786799
@@ -1543,7 +1556,7 @@ def peep_install(argv):
15431556 first_every_last(buckets[SatisfiedReq], *printers)
15441557
15451558 return ITS_FINE_ITS_FINE
1546- except (UnsupportedRequirementError, DownloadError) as exc:
1559+ except (UnsupportedRequirementError, InstallationError, DownloadError) as exc:
15471560 out(str(exc))
15481561 return SOMETHING_WENT_WRONG
15491562 finally:
@@ -1563,16 +1576,23 @@ def peep_port(paths):
15631576 print('Please specify one or more requirements files so I have '
15641577 'something to port.\n')
15651578 return COMMAND_LINE_ERROR
1579+
1580+ comes_from = None
15661581 for req in chain.from_iterable(
15671582 _parse_requirements(path, package_finder(argv)) for path in paths):
1583+ req_path, req_line = path_and_line(req)
15681584 hashes = [hexlify(urlsafe_b64decode((hash + '=').encode('ascii'))).decode('ascii')
1569- for hash in hashes_above(*path_and_line(req))]
1585+ for hash in hashes_above(req_path, req_line)]
1586+ if req_path != comes_from:
1587+ print()
1588+ print('# from %s' % req_path)
1589+ print()
1590+ comes_from = req_path
1591+
15701592 if not hashes:
15711593 print(req.req)
1572- elif len(hashes) == 1:
1573- print('%s --hash=sha256:%s' % (req.req, hashes[0]))
15741594 else:
1575- print('%s' % req.req, end='')
1595+ print('%s' % ( req.link if getattr( req, 'link', None) else req.req) , end='')
15761596 for hash in hashes:
15771597 print(' \\')
15781598 print(' --hash=sha256:%s' % hash, end='')
@@ -1617,7 +1637,7 @@ if __name__ == '__main__':
16171637 exit(main())
16181638 except Exception:
16191639 exception_handler(*sys.exc_info())
1620- exit(SOMETHING_WENT_WRONG )
1640+ exit(UNHANDLED_EXCEPTION )
16211641
16221642UNLIKELY_EOF
16231643 # -------------------------------------------------------------------------
@@ -1630,8 +1650,10 @@ UNLIKELY_EOF
16301650 # Report error. (Otherwise, be quiet.)
16311651 echo " Had a problem while downloading and verifying Python packages:"
16321652 echo " $PEEP_OUT "
1653+ rm -rf " $VENV_PATH "
16331654 exit 1
16341655 fi
1656+ echo " Installation succeeded."
16351657 fi
16361658 echo " Requesting root privileges to run letsencrypt..."
16371659 echo " " $SUDO " $VENV_BIN /letsencrypt" " $@ "
@@ -1653,10 +1675,11 @@ else
16531675 exit 0
16541676 fi
16551677
1656- echo " Checking for new version..."
1657- TEMP_DIR=$( TempDir)
1658- # ---------------------------------------------------------------------------
1659- cat << "UNLIKELY_EOF " > "$TEMP_DIR/fetch.py"
1678+ if [ " $NO_SELF_UPGRADE " != 1 ]; then
1679+ echo " Checking for new version..."
1680+ TEMP_DIR=$( TempDir)
1681+ # ---------------------------------------------------------------------------
1682+ cat << "UNLIKELY_EOF " > "$TEMP_DIR/fetch.py"
16601683"""Do downloading and JSON parsing without additional dependencies. ::
16611684
16621685 # Print latest released version of LE to stdout:
@@ -1785,25 +1808,36 @@ if __name__ == '__main__':
17851808 exit(main())
17861809
17871810UNLIKELY_EOF
1788- # ---------------------------------------------------------------------------
1789- DeterminePythonVersion
1790- REMOTE_VERSION=` " $LE_PYTHON " " $TEMP_DIR /fetch.py" --latest-version`
1791- if [ " $LE_AUTO_VERSION " != " $REMOTE_VERSION " ]; then
1792- echo " Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION ..."
1793-
1794- # Now we drop into Python so we don't have to install even more
1795- # dependencies (curl, etc.), for better flow control, and for the option of
1796- # future Windows compatibility.
1797- " $LE_PYTHON " " $TEMP_DIR /fetch.py" --le-auto-script " v$REMOTE_VERSION "
1798-
1799- # Install new copy of letsencrypt-auto. This preserves permissions and
1800- # ownership from the old copy.
1801- # TODO: Deal with quotes in pathnames.
1802- echo " Replacing letsencrypt-auto..."
1803- echo " " $SUDO cp " $TEMP_DIR /letsencrypt-auto" " $0 "
1804- $SUDO cp " $TEMP_DIR /letsencrypt-auto" " $0 "
1805- # TODO: Clean up temp dir safely, even if it has quotes in its path.
1806- rm -rf " $TEMP_DIR "
1807- fi # should upgrade
1808- " $0 " --no-self-upgrade " $@ "
1811+ # ---------------------------------------------------------------------------
1812+ DeterminePythonVersion
1813+ REMOTE_VERSION=` " $LE_PYTHON " " $TEMP_DIR /fetch.py" --latest-version`
1814+ if [ " $LE_AUTO_VERSION " != " $REMOTE_VERSION " ]; then
1815+ echo " Upgrading letsencrypt-auto $LE_AUTO_VERSION to $REMOTE_VERSION ..."
1816+
1817+ # Now we drop into Python so we don't have to install even more
1818+ # dependencies (curl, etc.), for better flow control, and for the option of
1819+ # future Windows compatibility.
1820+ " $LE_PYTHON " " $TEMP_DIR /fetch.py" --le-auto-script " v$REMOTE_VERSION "
1821+
1822+ # Install new copy of letsencrypt-auto.
1823+ # TODO: Deal with quotes in pathnames.
1824+ echo " Replacing letsencrypt-auto..."
1825+ # Clone permissions with cp. chmod and chown don't have a --reference
1826+ # option on OS X or BSD, and stat -c on Linux is stat -f on OS X and BSD:
1827+ echo " " $SUDO cp -p " $0 " " $TEMP_DIR /letsencrypt-auto.permission-clone"
1828+ $SUDO cp -p " $0 " " $TEMP_DIR /letsencrypt-auto.permission-clone"
1829+ echo " " $SUDO cp " $TEMP_DIR /letsencrypt-auto" " $TEMP_DIR /letsencrypt-auto.permission-clone"
1830+ $SUDO cp " $TEMP_DIR /letsencrypt-auto" " $TEMP_DIR /letsencrypt-auto.permission-clone"
1831+ # Using mv rather than cp leaves the old file descriptor pointing to the
1832+ # original copy so the shell can continue to read it unmolested. mv across
1833+ # filesystems is non-atomic, doing `rm dest, cp src dest, rm src`, but the
1834+ # cp is unlikely to fail (esp. under sudo) if the rm doesn't.
1835+ echo " " $SUDO mv -f " $TEMP_DIR /letsencrypt-auto.permission-clone" " $0 "
1836+ $SUDO mv -f " $TEMP_DIR /letsencrypt-auto.permission-clone" " $0 "
1837+ # TODO: Clean up temp dir safely, even if it has quotes in its path.
1838+ rm -rf " $TEMP_DIR "
1839+ fi # A newer version is available.
1840+ fi # Self-upgrading is allowed.
1841+
1842+ " $0 " --le-auto-phase2 " $@ "
18091843fi
0 commit comments