Add the beginnings of scripts to produce SDKs.
R=vardhan@google.com
Review URL: https://codereview.chromium.org/1701323003 .
diff --git a/sdk_build/README.md b/sdk_build/README.md
new file mode 100644
index 0000000..f8cc65a
--- /dev/null
+++ b/sdk_build/README.md
@@ -0,0 +1,4 @@
+# Tools/scripts/data for building SDKs
+
+This directory contains (or will contain) tools, scripts, and data for building
+SDKs (for various languages and platforms).
diff --git a/sdk_build/build_sdk.py b/sdk_build/build_sdk.py
new file mode 100755
index 0000000..e5a7638
--- /dev/null
+++ b/sdk_build/build_sdk.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Builds an SDK (in a specified target directory) from the (current) source
+repository (which should not be dirty) and a given "specification" file."""
+
+
+import argparse
+from pylib.errors import FatalError
+from pylib.git import Git, IsGitTreeDirty, SanityCheckGit, GitLsFiles
+import os
+import shutil
+import sys
+
+
+def _CopyFiles(source_path, dest_path, **kwargs):
+ """Copies files from the source git repository (the current working directory
+ should be the root of this repository) to the destination path. |source_path|
+ and the keyword arguments are as for the arguments of |GitLsFiles|.
+ |dest_path| should be the "root" destination path. Note that a file such as
+ <source_path>/foo/bar/baz.quux is copied to <dest_path>/foo/bar/baz.quux."""
+
+ # Normalize the source path. Note that this strips any trailing '/'.
+ source_path = os.path.normpath(source_path)
+ source_files = GitLsFiles(source_path, **kwargs)
+ for source_file in source_files:
+ rel_path = source_file[len(source_path) + 1:]
+ dest_file = os.path.join(dest_path, rel_path)
+ try:
+ os.makedirs(os.path.dirname(dest_file))
+ except OSError:
+ pass
+ shutil.copyfile(source_file, dest_file)
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Constructs an SDK from a specification")
+ parser.add_argument("--allow-dirty-tree", dest="allow_dirty_tree",
+ action="store_true",
+ help="proceed even if the source tree is dirty")
+ parser.add_argument("sdk_spec_file", metavar="sdk_spec_file.sdk",
+ type=argparse.FileType("rb"),
+ help="spec file for the SDK to build")
+ parser.add_argument("target_dir",
+ help="target directory (must not already exist)")
+ args = parser.parse_args()
+
+ target_dir = os.path.abspath(args.target_dir)
+
+ # CD to the "src" directory (we should currently be in src/sdk_build).
+ src_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
+ os.chdir(src_dir)
+
+ SanityCheckGit()
+
+ if not args.allow_dirty_tree and IsGitTreeDirty():
+ FatalError("tree appears to be dirty")
+
+ try:
+ os.mkdir(target_dir)
+ except OSError:
+ FatalError("failed to create target directory %s" % target_dir)
+
+ def CopyFilesToTargetDir(source_path, rel_dest_path, **kwargs):
+ return _CopyFiles(source_path, os.path.join(target_dir, rel_dest_path),
+ **kwargs)
+
+ execution_globals = {"CopyFiles": CopyFilesToTargetDir,
+ "FatalError": FatalError,
+ "GitLsFiles": GitLsFiles}
+ exec args.sdk_spec_file in execution_globals
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/sdk_build/data/cpp/cpp.sdk b/sdk_build/data/cpp/cpp.sdk
new file mode 100644
index 0000000..f6f4cec
--- /dev/null
+++ b/sdk_build/data/cpp/cpp.sdk
@@ -0,0 +1,20 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file contains steps for "building" a C/C++ SDK. It is processed by
+# //mojo/sdk_build/build_sdk.py.
+# TODO(vtl): This isn't done yet.
+
+EXCLUDE_FILES=[".*", "*.gn", "*.gni", "PRESUBMIT.py", "*_win.*"]
+EXCLUDE_PATHS=["*/tests/"]
+
+CopyFiles("mojo/public/c", "third_party/mojo/public/c", recursive=True,
+ exclude_file_patterns=EXCLUDE_FILES,
+ exclude_path_patterns=EXCLUDE_PATHS)
+CopyFiles("mojo/public/cpp", "third_party/mojo/public/cpp", recursive=True,
+ exclude_file_patterns=EXCLUDE_FILES,
+ exclude_path_patterns=EXCLUDE_PATHS+
+ ["mojo/public/cpp/test_support/*"])
+CopyFiles("mojo/public", "third_party/mojo/public", recursive=False,
+ exclude_file_patterns=EXCLUDE_FILES)
diff --git a/sdk_build/pylib/__init__.py b/sdk_build/pylib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sdk_build/pylib/__init__.py
diff --git a/sdk_build/pylib/errors.py b/sdk_build/pylib/errors.py
new file mode 100644
index 0000000..f90abfd
--- /dev/null
+++ b/sdk_build/pylib/errors.py
@@ -0,0 +1,15 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Error-handling support functions."""
+
+
+import os.path
+import sys
+
+
+def FatalError(message):
+ print >> sys.stderr, "%s: fatal error: %s" % (os.path.basename(sys.argv[0]),
+ message)
+ sys.exit(1)
diff --git a/sdk_build/pylib/git.py b/sdk_build/pylib/git.py
new file mode 100644
index 0000000..fa09880
--- /dev/null
+++ b/sdk_build/pylib/git.py
@@ -0,0 +1,69 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Git support functions."""
+
+
+from errors import FatalError
+import fnmatch
+import os.path
+import subprocess
+
+
+def Git(subcommand, *args):
+ """Runs "git <subcommand> <args...>" and returns the output, including
+ standard error. Raises |OSError| if it fails to run git at all and
+ |subprocess.CalledProcessError| if the command returns failure (nonzero)."""
+
+ return subprocess.check_output(
+ ('git', subcommand) + args, stderr=subprocess.STDOUT)
+
+
+def SanityCheckGit():
+ """Does a sanity check that git is available and the current working directory
+ is in a git repository (exits with an error message on failure)."""
+
+ try:
+ Git("status")
+ except OSError:
+ FatalError("failed to run git -- is it in your PATH?")
+ except subprocess.CalledProcessError:
+ FatalError("\"git status\" failed -- is %s in a git repository?" %
+ os.getcwd())
+
+
+def IsGitTreeDirty():
+ """Checks if the tree looks dirty (returning true if it is)."""
+
+ try:
+ Git("diff-index", "--quiet", "HEAD")
+ except subprocess.CalledProcessError:
+ return True
+ return False
+
+
+def GitLsFiles(path, recursive=True, exclude_file_patterns=None,
+ exclude_path_patterns=None):
+ """Returns a list of files under the given path (the filenames will include
+ the full path). If |recursive| is true (the default), then this list will
+ include all files (recursively); if not, it will only include the files "at"
+ the exact path. |exclude_file_patterns| may be a list of shell-style wildcards
+ of filenames to exclude. Similarly, |exclude_path_patterns| may be a list of
+ shell-style wildcards of paths to exclude (note: to make it easier to match
+ subtrees, a trailing '/' is added to the path for matching purposes)."""
+
+ # Files are "null-terminated". This results in an extra empty string at the
+ # end. "Luckily", in the empty case, we also get an empty string.
+ result = Git("ls-files", "-z", path).split("\0")[:-1]
+ if not recursive:
+ result = [f for f in result if os.path.dirname(f) == path]
+ if exclude_file_patterns:
+ for p in exclude_file_patterns:
+ result = [f for f in result
+ if not fnmatch.fnmatch(os.path.basename(f), p)]
+ if exclude_path_patterns:
+ for p in exclude_path_patterns:
+ result = [f for f in result
+ if not fnmatch.fnmatch(os.path.dirname(f) + "/", p)]
+ return result