Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Narvaez <dwnarvaez@gmail.com>2012-12-16 16:53:36 (GMT)
committer Daniel Narvaez <dwnarvaez@gmail.com>2012-12-16 16:53:36 (GMT)
commit39f3d8a9428e031c4bdb0cc9a26f2fb1df9a7520 (patch)
tree7947f1413318b4379bae8e6c28fc92e61d38d3ee
parentc6206d0f80d5961b5d52a5b03765acdad2c22f7e (diff)
Add a distribute command
It builds and uploads releases.
-rw-r--r--Makefile.commands3
-rwxr-xr-xcommands/distribute12
-rw-r--r--config/modules/sugar.json3
-rw-r--r--devbot/build.py93
-rw-r--r--devbot/config.py14
-rw-r--r--devbot/git.py47
-rw-r--r--devbot/release.py47
7 files changed, 210 insertions, 9 deletions
diff --git a/Makefile.commands b/Makefile.commands
index 78805a8..be82830 100644
--- a/Makefile.commands
+++ b/Makefile.commands
@@ -27,6 +27,9 @@ bug-report:
clean:
@$(COMMANDS_DIR)/clean
+distribute:
+ @$(COMMANDS_DIR)/distribute
+
build-%:
@$(COMMANDS_DIR)/build $*
diff --git a/commands/distribute b/commands/distribute
new file mode 100755
index 0000000..1da8b0b
--- /dev/null
+++ b/commands/distribute
@@ -0,0 +1,12 @@
+#!/usr/bin/python -u
+
+import sys
+
+import common
+
+from devbot import build
+
+common.setup()
+
+if not build.distribute():
+ sys.exit(1)
diff --git a/config/modules/sugar.json b/config/modules/sugar.json
index 2c119e5..20a54c3 100644
--- a/config/modules/sugar.json
+++ b/config/modules/sugar.json
@@ -44,6 +44,7 @@
},
{
"name": "sugar-runner",
- "repo": "git://git.sugarlabs.org/sugar-runner/sugar-runner.git"
+ "repo": "git://git.sugarlabs.org/sugar-runner/sugar-runner.git",
+ "distribute": true
}
]
diff --git a/devbot/build.py b/devbot/build.py
index ee15192..9823310 100644
--- a/devbot/build.py
+++ b/devbot/build.py
@@ -1,14 +1,20 @@
import fnmatch
+import re
import os
import multiprocessing
import shutil
import subprocess
+from distutils.sysconfig import parse_makefile
from devbot import command
from devbot import config
from devbot import environ
from devbot import state
from devbot import utils
+from devbot import release
+
+_builders = {}
+_distributors = {}
def build_one(module_name):
environ.setup()
@@ -72,6 +78,16 @@ def build():
return True
+def distribute():
+ environ.setup()
+
+ for module in config.load_modules():
+ if module.distribute:
+ if not _distribute_module(module):
+ break
+
+ return True
+
def clean():
_rmtree(config.install_dir)
_rmtree(config.prefix_dir)
@@ -134,10 +150,53 @@ def _build_autotools(module, log):
_unlink_libtool_files()
+_builders["autotools"] = _build_autotools
+
def _build_activity(module, log):
setup = os.path.join(module.get_source_dir(), "setup.py")
command.run([setup, "install", "--prefix", config.prefix_dir], log)
+_builders["activity"] = _build_activity
+
+def _distribute_autotools(module):
+ makefile = parse_makefile("Makefile")
+ filename = makefile["DIST_ARCHIVES"]
+ version = makefile["VERSION"]
+
+ git_module = module.get_git_module()
+
+ version_revision = None
+ description = git_module.describe()
+ if description != "v%s" % version:
+ match = re.match(r"(v[\d\.]+)", description)
+ if match is None:
+ print "No version tag was found"
+ return False
+ else:
+ version_revision = match.groups()[0]
+
+ if version_revision is not None:
+ git_module.checkout(version_revision)
+
+ command.run(["make", "distcheck"])
+
+ result = False
+
+ if not release.exists(module, filename):
+ path = os.path.join(os.getcwd(), filename)
+ if release.upload(module, path):
+ annotation = git_module.get_annotation("v%s" % version)
+ result = release.announce(module, filename, version, annotation)
+ else:
+ print "Release already uploaded"
+
+ if version_revision is not None:
+ git_module.checkout()
+
+ return result
+
+_distributors["autotools"] = _distribute_autotools
+
def _build_module(module, log=None):
print "\n=== Building %s ===\n" % module.name
@@ -159,14 +218,11 @@ def _build_module(module, log=None):
os.chdir(source_dir)
try:
- if os.path.exists(os.path.join(source_dir, "setup.py")):
- _build_activity(module, log)
- elif os.path.exists(os.path.join(source_dir, "autogen.sh")):
- _build_autotools(module, log)
- else:
- print "The source directory has unexpected content, please " \
- "delete it and pull\nthe source again."
+ build_system = module.get_build_system()
+ if build_system is None:
return False
+
+ _builders[build_system](module, log)
except subprocess.CalledProcessError:
return False
@@ -174,6 +230,29 @@ def _build_module(module, log=None):
return True
+def _distribute_module(module, log=None):
+ print "\n=== Distribute %s ===\n" % module.name
+
+ build_dir = module.get_build_dir()
+
+ if not os.path.exists(build_dir):
+ print "Build directory does not exist. Please build before " \
+ "distributing."
+ return False
+
+ os.chdir(build_dir)
+
+ try:
+ build_system = module.get_build_system()
+ if build_system is None:
+ return False
+
+ _distributors[build_system](module)
+ except subprocess.CalledProcessError:
+ return False
+
+ return True
+
def _rmtree(dir):
print "Deleting %s" % dir
shutil.rmtree(dir, ignore_errors=True)
diff --git a/devbot/config.py b/devbot/config.py
index 2f9999c..93c82f7 100644
--- a/devbot/config.py
+++ b/devbot/config.py
@@ -38,6 +38,7 @@ class Module:
self.options = info.get("options", [])
self.options_evaluated = info.get("options_evaluated", [])
self.has_tests = info.get("has_tests", False)
+ self.distribute = info.get("distribute", False)
if get_pref("BUILD_IN_SOURCE"):
self.out_of_source = False
@@ -50,7 +51,7 @@ class Module:
def get_build_dir(self):
return os.path.join(get_build_dir(), self.name)
- def get_commit_id(self):
+ def get_commit_id(self, tag="HEAD"):
if not os.path.exists(self.get_source_dir()):
return None
@@ -61,6 +62,17 @@ class Module:
remote=self.repo, branch=self.branch, tag=self.tag,
retry=10)
+ def get_build_system(self):
+ source_dir = self.get_source_dir()
+ if os.path.exists(os.path.join(source_dir, "setup.py")):
+ return "activity"
+ elif os.path.exists(os.path.join(source_dir, "autogen.sh")):
+ return "autotools"
+ else:
+ print "The source directory has unexpected content, please " \
+ "delete it and pull\nthe source again."
+ return None
+
def _ensure_dir(dir):
if not os.path.exists(dir):
os.mkdir(dir)
diff --git a/devbot/git.py b/devbot/git.py
index b9008af..1e361f0 100644
--- a/devbot/git.py
+++ b/devbot/git.py
@@ -1,7 +1,20 @@
import os
+import subprocess
from devbot import command
+def _chdir(func):
+ def wrapped(*args, **kwargs):
+ orig_cwd = os.getcwd()
+
+ os.chdir(args[0].local)
+ result = func(*args, **kwargs)
+ os.chdir(orig_cwd)
+
+ return result
+
+ return wrapped
+
class Module:
def __init__(self, path=None, name=None, remote=None,
branch="master", tag=None, retry=10):
@@ -45,6 +58,40 @@ class Module:
command.run(["git", "merge", "--ff-only",
"origin/%s" % self._branch])
+ @_chdir
+ def checkout(self, revision=None):
+ if revision is None:
+ revision = self.tag
+ if revision is None:
+ revision = self._branch
+
+ command.run(["git", "checkout", revision])
+
+ @_chdir
+ def describe(self):
+ return subprocess.check_output(["git", "describe"]).strip()
+
+ @_chdir
+ def get_annotation(self, tag):
+ # FIXME this is fragile, there must be a better way
+
+ show = subprocess.check_output(["git", "show", tag])
+
+ annotation = []
+ for line in show.split("\n"):
+ ignore = False
+ for start in ["tag ", "Tagger: ", "Date: "]:
+ if line.startswith(start):
+ ignore = True
+
+ if line.startswith("commit "):
+ break
+
+ if not ignore:
+ annotation.append(line)
+
+ return "\n".join(annotation)
+
def clean(self):
try:
os.chdir(self.local)
diff --git a/devbot/release.py b/devbot/release.py
new file mode 100644
index 0000000..278cbf5
--- /dev/null
+++ b/devbot/release.py
@@ -0,0 +1,47 @@
+import os
+import subprocess
+import tempfile
+
+upload_host = "shell.sugarlabs.org"
+#upload_root = "/upload/sources/sucrose/glucose"
+upload_root = "~/"
+download_uri = "http://download.sugarlabs.org/sources/sucrose/glucose"
+#announce_to = "sugar-devel@lists.sugarlabs.org"
+announce_to = "dwnarvaez@gmail.com"
+
+def exists(module, filename):
+ release_path = os.path.join(upload_root, module.name, filename)
+ result = subprocess.call(["ssh", upload_host, "test", "-f", release_path])
+ return result == 0
+
+def upload(module, path):
+ upload_path = os.path.join(upload_root, module.name)
+ upload_dest = "%s:%s" % (upload_host, upload_path)
+ return subprocess.call(["scp", path, upload_dest]) == 0
+
+def announce(module, filename, version, annotation):
+ fd, announce_path = tempfile.mkstemp("announce-")
+
+ with os.fdopen(fd, "w") as f:
+ f.write("From: %s\n" % _get_email())
+ f.write("To: %s\n" % announce_to)
+ f.write("Subject: [RELEASE] %s-%s\n" % (module.name, version))
+
+ f.write("\n%s\n" % annotation)
+ f.write("== Source ==\n\n")
+ f.write("%s/%s/%s" % (download_uri, module.name, filename))
+
+ result = False
+
+ upload_dest = "%s:~" % upload_host
+ if subprocess.call(["scp", announce_path, upload_dest]) == 0:
+ if subprocess.call(["ssh", upload_host, "sendmail", "-t",
+ "<", os.path.basename(announce_path)]):
+ result = True
+
+ os.unlink(announce_path)
+
+ return result
+
+def _get_email():
+ return subprocess.check_output(['git', 'config', 'user.email']).strip()