[MediaWiki-commits] [Gerrit] Convert scap-1 to python - change (mediawiki...scap)

2014-02-14 Thread jenkins-bot (Code Review)
jenkins-bot has submitted this change and it was merged.

Change subject: Convert scap-1 to python
..


Convert scap-1 to python

Convert the scap-1 bash script to a pair of python functions.
sync_common contains the core business logic and sync_common_main
provides a wrapper with command line arguments and error logging.

This patch also introduces a utility function for constructing sudo
calls and a small number of doc tests.

Change-Id: Ida1cc1e149383cf26388494fb642e738da30be12
---
M bin/scap-1
M scap/__init__.py
A scap/main.py
M scap/scap.py
A scap/tasks.py
M scap/utils.py
6 files changed, 176 insertions(+), 32 deletions(-)

Approvals:
  Ori.livneh: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/bin/scap-1 b/bin/scap-1
index 913cc2f..26835e5 100755
--- a/bin/scap-1
+++ b/bin/scap-1
@@ -1,31 +1,17 @@
-#!/bin/bash
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Sync MW_COMMON
+#
+# Copyright © 2014 Wikimedia Foundation and contributors
 
-. /usr/local/lib/mw-deployment-vars.sh
+import os
+import sys
 
-if [ ! -d "${MW_COMMON}" ];then
-   if ! install -d -o mwdeploy -g mwdeploy "${MW_COMMON}"; then
-   echo "Unable to create ${MW_COMMON}, please re-run this script 
as root."
-   exit 1
-   fi
-fi
+# Add scap package to search path
+script = os.path.realpath(sys.argv[0])
+scap_src = os.path.dirname(os.path.dirname(script))
+sys.path.append(scap_src)
 
-if [ ! -d /usr/local/apache/uncommon ];then
-   if ! install -d -o mwdeploy -g mwdeploy /usr/local/apache/uncommon; then
-   echo "Unable to create /usr/local/apache/uncommon, please 
re-run this script as root."
-   exit 1
-   fi
-fi
-
-RSYNC_SERVERS="$1"
-SERVER=
-if [ -n "$RSYNC_SERVERS" ]; then
-   SERVER=$(sudo /usr/local/bin/find-nearest-rsync $RSYNC_SERVERS)
-fi
-if [ -z "$SERVER" ]; then
-   SERVER="${MW_RSYNC_HOST}"
-fi
-
-sudo -u mwdeploy MW_VERSIONS_SYNC="$MW_VERSIONS_SYNC" 
MW_SCAP_BETA="$MW_SCAP_BETA" /usr/local/bin/scap-2 "$SERVER"
-
-echo Done
-exit 0
+import scap
+sys.exit(scap.sync_common())
diff --git a/scap/__init__.py b/scap/__init__.py
index c2ccf8d..a0a9752 100644
--- a/scap/__init__.py
+++ b/scap/__init__.py
@@ -7,8 +7,12 @@
 
 """
 from .scap import scap
+from .main import sync_common
 from . import log
 
-__all__ = ('scap',)
+__all__ = (
+'scap',
+'sync_common',
+)
 
 log.setup_loggers()
diff --git a/scap/main.py b/scap/main.py
new file mode 100644
index 000..796b5ea
--- /dev/null
+++ b/scap/main.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+"""
+scap.main
+~~
+Command wrappers for scap tasks
+
+"""
+import argparse
+import logging
+import sys
+
+from . import tasks
+from . import utils
+
+
+def sync_common():
+"""Command wrapper for :func:`tasks.sync_common`
+
+:returns: Integer exit status suitable for use with ``sys.exit``
+"""
+logger = logging.getLogger('sync_common')
+try:
+
+parser = argparse.ArgumentParser(description='Sync MW_COMMON')
+parser.add_argument('-c', '--conf',
+dest='conf_file', default='/usr/local/lib/mw-deployment-vars.sh',
+help='Path to configuration file')
+parser.add_argument('servers', nargs=argparse.REMAINDER,
+help='Rsync server(s) to copy from')
+args = parser.parse_args()
+args.cfg = utils.get_config(args.conf_file)
+
+tasks.sync_common(args.cfg, args.servers)
+return 0
+
+except SystemExit:
+# Triggered by sys.exit() calls
+raise
+
+except KeyboardInterrupt:
+# Handle ctrl-c from interactive user
+logger.warning('sync_common aborted')
+return 1
+
+except:
+# Handle all unhandled exceptions and errors
+exctype, value = sys.exc_info()[:2]
+logger.error('sync_common failed: <%s> %s', exctype.__name__, value)
+return 1
diff --git a/scap/scap.py b/scap/scap.py
index 520e8f5..a564d69 100644
--- a/scap/scap.py
+++ b/scap/scap.py
@@ -15,6 +15,7 @@
 import time
 
 from . import log
+from . import tasks
 from . import utils
 
 
@@ -59,7 +60,7 @@
 # Update the current machine so that serialization works. Push
 # wikiversions.dat changes so mwversionsinuse, set-group-write,
 # and mwscript work with the right version of the files.
-subprocess.check_call('/usr/local/bin/sync-common')
+tasks.sync_common(dict(args.cfg.items() + env.items()))
 
 # Update list of extension message files and regenerate the
 # localisation cache.
diff --git a/scap/tasks.py b/scap/tasks.py
new file mode 100644
index 000..fed4081
--- /dev/null
+++ b/scap/tasks.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+"""
+scap.tasks
+~~
+Contains functions implementing scap tasks
+
+"""
+import logging
+import os
+import socket
+import subprocess
+
+from . import utils
+
+
+def sync_com

[MediaWiki-commits] [Gerrit] Convert scap-1 to python - change (mediawiki...scap)

2014-02-10 Thread BryanDavis (Code Review)
BryanDavis has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/112487

Change subject: Convert scap-1 to python
..

Convert scap-1 to python

Convert the scap-1 bash script to a pair of python functions.
sync_common contains the core business logic and sync_common_main
provides a wrapper with command line arguments and error logging.

This patch also introduces a utility function for constructing sudo
calls and a small number of doc tests.

Change-Id: Ida1cc1e149383cf26388494fb642e738da30be12
---
M bin/scap-1
M scap/__init__.py
M scap/scap.py
A scap/support.py
M scap/utils.py
5 files changed, 156 insertions(+), 32 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/tools/scap 
refs/changes/87/112487/1

diff --git a/bin/scap-1 b/bin/scap-1
index 913cc2f..0eda1e8 100755
--- a/bin/scap-1
+++ b/bin/scap-1
@@ -1,31 +1,17 @@
-#!/bin/bash
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Sync MW_COMMON
+#
+# Copyright © 2014 Wikimedia Foundation and contributors
 
-. /usr/local/lib/mw-deployment-vars.sh
+import os
+import sys
 
-if [ ! -d "${MW_COMMON}" ];then
-   if ! install -d -o mwdeploy -g mwdeploy "${MW_COMMON}"; then
-   echo "Unable to create ${MW_COMMON}, please re-run this script 
as root."
-   exit 1
-   fi
-fi
+# Add scap package to search path
+script = os.path.realpath(sys.argv[0])
+scap_src = os.path.dirname(os.path.dirname(script))
+sys.path.append(scap_src)
 
-if [ ! -d /usr/local/apache/uncommon ];then
-   if ! install -d -o mwdeploy -g mwdeploy /usr/local/apache/uncommon; then
-   echo "Unable to create /usr/local/apache/uncommon, please 
re-run this script as root."
-   exit 1
-   fi
-fi
-
-RSYNC_SERVERS="$1"
-SERVER=
-if [ -n "$RSYNC_SERVERS" ]; then
-   SERVER=$(sudo /usr/local/bin/find-nearest-rsync $RSYNC_SERVERS)
-fi
-if [ -z "$SERVER" ]; then
-   SERVER="${MW_RSYNC_HOST}"
-fi
-
-sudo -u mwdeploy MW_VERSIONS_SYNC="$MW_VERSIONS_SYNC" 
MW_SCAP_BETA="$MW_SCAP_BETA" /usr/local/bin/scap-2 "$SERVER"
-
-echo Done
-exit 0
+import scap
+sys.exit(scap.sync_common_main())
diff --git a/scap/__init__.py b/scap/__init__.py
index c2ccf8d..9d1b20a 100644
--- a/scap/__init__.py
+++ b/scap/__init__.py
@@ -7,8 +7,12 @@
 
 """
 from .scap import scap
+from .support import sync_common_main
 from . import log
 
-__all__ = ('scap',)
+__all__ = [
+'scap',
+'sync_common_main',
+]
 
 log.setup_loggers()
diff --git a/scap/scap.py b/scap/scap.py
index 7750f3d..c34f075 100644
--- a/scap/scap.py
+++ b/scap/scap.py
@@ -15,6 +15,7 @@
 import time
 
 from . import log
+from . import support
 from . import utils
 
 
@@ -59,7 +60,7 @@
 # Update the current machine so that serialization works. Push
 # wikiversions.dat changes so mwversionsinuse, set-group-write,
 # and mwscript work with the right version of the files.
-subprocess.check_call('/usr/local/bin/sync-common')
+support.sync_common(args.cfg)
 
 # Update list of extension message files and regenerate the
 # localisation cache.
diff --git a/scap/support.py b/scap/support.py
new file mode 100644
index 000..63b4f2c
--- /dev/null
+++ b/scap/support.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+"""
+scap.support
+~~
+Contains high level functions that support scap.
+
+"""
+import argparse
+import logging
+import os
+import subprocess
+import sys
+
+from . import utils
+
+
+def sync_common(cfg, sync_from=None):
+"""Sync MW_COMMON
+
+:param cfg: Global configuration
+:type cfg: dict
+:param sync_from: Rsync servers to fetch from
+:type sync_from: str
+"""
+target = cfg['MW_COMMON']
+if not os.path.isdir(target):
+raise Exception(('rsync target directory {0} not found. '
+'Ask root to create it.').format(target))
+
+# FIXME: Why is this hardcoded?
+# FIXME: Why is this even here? uncommon isn't touched
+uncommon = '/usr/local/apache/uncommon'
+if not os.path.isdir(uncommon):
+raise Exception(('directory {0} not found. '
+'Ask root to create it.').format(uncommon))
+
+server = None
+if sync_from:
+server = subprocess.check_output(utils.sudo_args(
+['/usr/local/bin/find-nearest-rsync'] + sync_from.split()))
+if server is None:
+server = cfg['MW_RSYNC_HOST']
+
+subprocess.check_call(utils.sudo_args(
+['/usr/local/bin/scap-2', server], user='mwdeploy',
+exports={
+'MW_VERSIONS_SYNC': cfg['MW_VERSIONS_SYNC'],
+'MW_SCAP_BETA': cfg['MW_SCAP_BETA'],
+}))
+
+
+def sync_common_main():
+"""Command wrapper for :func:`sync_common`
+
+:returns: Integer exit status suitable for use with ``sys.exit``
+"""
+logger = logging.getLogger('scap-1')
+try:
+
+parser = argparse.ArgumentParser(description='Sync MW_COMMON')
+