def Validate(self): for libc in self.DISABLED_LIBC: if libc not in configuration.VALID_LIBC: raise Error('%s: invalid libc: %s' % (self.info, libc)) for toolchain in self.DISABLED_TOOLCHAIN: if '/' in toolchain: toolchain, arch = toolchain.split('/') if arch not in util.arch_to_pkgarch: raise Error('%s: invalid architecture: %s' % (self.info, arch)) if toolchain not in configuration.VALID_TOOLCHAINS: raise Error('%s: invalid toolchain: %s' % (self.info, toolchain)) for arch in self.DISABLED_ARCH: if arch not in util.arch_to_pkgarch: raise Error('%s: invalid architecture: %s' % (self.info, arch)) if '_' in self.NAME: raise Error('%s: package NAME cannot contain underscores' % self.info) if self.NAME != self.NAME.lower(): raise Error( '%s: package NAME cannot contain uppercase characters' % self.info) if '_' in self.VERSION: raise Error('%s: package VERSION cannot contain underscores' % self.info) if self.DISABLED_ARCH and self.ARCH is not None: raise Error('%s: contains both ARCH and DISABLED_ARCH' % self.info)
def __init__(self, pkg_root, config=None): super(SourcePackage, self).__init__() if config is None: config = configuration.Configuration() self.config = config self.root = os.path.abspath(pkg_root) info_file = os.path.join(self.root, 'pkg_info') if not os.path.isdir(self.root) or not os.path.exists(info_file): raise Error('Invalid package folder: %s' % pkg_root) super(SourcePackage, self).__init__(info_file) if self.NAME != os.path.basename(self.root): raise Error('%s: package NAME must match directory name' % self.info)
def run_build_sh(self): build_port = os.path.join(paths.TOOLS_DIR, 'build_port.sh') cmd = [build_port] if os.name == 'nt': cmd = ['bash', build_port] if self.config.toolchain == 'emscripten': util.setup_emscripten() env = os.environ.copy() env['TOOLCHAIN'] = self.config.toolchain env['NACL_ARCH'] = self.config.arch env['NACL_DEBUG'] = self.config.debug and '1' or '0' env['NACL_SDK_ROOT'] = util.get_sdk_root() if os.name == 'nt' and self.config.toolchain == 'emscripten': # MinGW : C:\dir1\dir2\ -> /C/dir1/dir2/ # Cygwin : C:\dir1\dir2\ -> /cygdrive/c/dir1/dir2 def mingw_fix_path(path): return '/' + path.replace(':', '').replace('\\', '/') env['EMSCRIPTEN'] = mingw_fix_path(env['EMSCRIPTEN']) env['EM_CONFIG'] = mingw_fix_path(env['EM_CONFIG']) rtn = subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=self.root, env=env) if rtn != 0: raise Error('Build failed: %s' % self.info_string())
def git_clone(self): """Create a clone of the upstream repo in the build directory. This operation will only require a network connection if the local git mirror is out-of-date.""" stamp_file = self.get_extract_stamp() stamp_content = 'GITURL=%s' % self.URL patch_file = self.get_patch_file() if os.path.exists(patch_file): patch_checksum = util.hash_file(patch_file) stamp_content += ' PATCH=%s' % patch_checksum stamp_content += '\n' dest = self.get_build_location() if os.path.exists(self.get_build_location()): if stamp_contents_match(stamp_file, stamp_content): return raise Error('Upstream archive or patch has changed.\n' + "Please remove existing checkout and try again: '%s'" % dest) util.log_heading('Cloning') # Ensure local mirror is up-to-date git_mirror, git_commit = self.git_clone_to_mirror() # Clone from the local mirror. run_git_cmd(None, ['clone', git_mirror, dest]) run_git_cmd(dest, ['reset', '--hard', git_commit]) # Set the origing to the original URL so it is possible to push directly # from the build tree. run_git_cmd(dest, ['remote', 'set-url', 'origin', self.URL.split('@')[0]]) self.remove_stamps() write_stamp(stamp_file, stamp_content)
def Extract(self): """Extract the package archive into its build location. This method assumes the package has already been downloaded. """ if self.IsGitUpstream(): self.GitClone() return archive = self.DownloadLocation() if not archive: self.Log('Skipping extract; No upstream archive') return dest = self.GetBuildLocation() output_path, new_foldername = os.path.split(dest) util.Makedirs(output_path) # Check existing stamp file contents stamp_file = self.GetExtractStamp() stamp_contents = self.GetExtractStampContent() if os.path.exists(dest): if StampContentsMatch(stamp_file, stamp_contents): Log('Already up-to-date: %s' % util.RelPath(dest)) return raise Error("Upstream archive or patch has changed.\n" + "Please remove existing checkout and try again: '%s'" % dest) util.LogHeading('Extracting') util.Makedirs(paths.OUT_DIR) tmp_output_path = tempfile.mkdtemp(dir=paths.OUT_DIR) try: ExtractArchive(archive, tmp_output_path) src = os.path.join(tmp_output_path, new_foldername) if not os.path.isdir(src): raise Error('Archive contents not found: %s' % src) LogVerbose("renaming '%s' -> '%s'" % (src, dest)) os.rename(src, dest) finally: util.RemoveTree(tmp_output_path) self.RemoveStamps() WriteStamp(stamp_file, stamp_contents)
def extract(self): """Extract the package archive into its build location. This method assumes the package has already been downloaded. """ if self.is_git_upstream(): self.git_clone() return archive = self.download_location() if not archive: self.log('Skipping extract; No upstream archive') return dest = self.get_build_location() output_path, new_foldername = os.path.split(dest) util.makedirs(output_path) # Check existing stamp file contents stamp_file = self.get_extract_stamp() stamp_contents = self.get_extract_stamp_content() if os.path.exists(dest): if stamp_contents_match(stamp_file, stamp_contents): log('Already up-to-date: %s' % util.rel_path(dest)) return raise Error("Upstream archive or patch has changed.\n" + "Please remove existing checkout and try again: '%s'" % dest) util.log_heading('Extracting') util.makedirs(paths.OUT_DIR) tmp_output_path = tempfile.mkdtemp(dir=paths.OUT_DIR) try: extract_archive(archive, tmp_output_path) src = os.path.join(tmp_output_path, new_foldername) if not os.path.isdir(src): raise Error('Archive contents not found: %s' % src) log_verbose("renaming '%s' -> '%s'" % (src, dest)) os.rename(src, dest) finally: util.remove_tree(tmp_output_path) self.remove_stamps() write_stamp(stamp_file, stamp_contents)
def RunCmd(self, cmd, **args): try: subprocess.check_call(cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=self.GetBuildLocation(), **args) except subprocess.CalledProcessError as e: raise Error(e)
def run_cmd(self, cmd, **args): try: subprocess.check_call(cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=self.get_build_location(), **args) except subprocess.CalledProcessError as e: raise Error(e)
def ExtractArchive(archive, destination): ext = os.path.splitext(archive)[1] if ext in ('.gz', '.tgz', '.bz2', '.xz'): cmd = ['tar', 'xf', archive, '-C', destination] elif ext in ('.zip', ): cmd = ['unzip', '-q', '-d', destination, archive] else: raise Error('unhandled extension: %s' % ext) LogVerbose(cmd) subprocess.check_call(cmd)
def run_git_cmd(directory, cmd, error_ok=False): cmd = ['git'] + cmd log_verbose('%s' % ' '.join(cmd)) p = subprocess.Popen(cmd, cwd=directory, stderr=subprocess.PIPE, stdout=subprocess.PIPE) stdout, stderr = p.communicate() if not error_ok and p.returncode != 0: if stdout: log(stdout) if stderr: log(stderr) raise Error('git command failed: %s' % cmd) trace('git exited with %d' % p.returncode) return p.returncode
def run_build_sh(self): build_port = os.path.join(paths.TOOLS_DIR, 'build_port.sh') cmd = [build_port] if self.config.toolchain == 'emscripten': util.setup_emscripten() env = os.environ.copy() env['TOOLCHAIN'] = self.config.toolchain env['NACL_ARCH'] = self.config.arch env['NACL_DEBUG'] = self.config.debug and '1' or '0' env['NACL_SDK_ROOT'] = util.get_sdk_root() rtn = subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=self.root, env=env) if rtn != 0: raise Error('Build failed: %s' % self.info_string())
def CreatePackage(package_name, config=None): """Create a Package object given a package name or path. Returns: Package object """ if os.path.isdir(package_name): return SourcePackage(package_name, config) for subdir in DEFAULT_LOCATIONS: pkg_root = os.path.join(paths.NACLPORTS_ROOT, subdir, package_name) info = os.path.join(pkg_root, 'pkg_info') if os.path.exists(info): return SourcePackage(pkg_root, config) raise Error("Package not found: %s" % package_name)
def add_package_dep(dep_dict, dep): dep_dict['origin'] = dep if os.path.isdir(dep): pkg = package.Package(info_file=os.path.join(dep, 'pkg_info')) dep_dict['version'] = pkg.VERSION return for subdir in DEFAULT_LOCATIONS: pkg_info_file = os.path.join(paths.NACLPORTS_ROOT, subdir, dep, 'pkg_info') if os.path.exists(pkg_info_file): dep_dict['version'] = package.Package(info_file=pkg_info_file).VERSION return raise Error("Package not found: %s" % dep)
def RunBuildSh(self): build_port = os.path.join(paths.TOOLS_DIR, 'build_port.sh') cmd = [build_port] if self.config.toolchain == 'emscripten': util.SetupEmscripten() env = os.environ.copy() env['TOOLCHAIN'] = self.config.toolchain env['NACL_ARCH'] = self.config.arch env['NACL_DEBUG'] = self.config.debug and '1' or '0' env['NACL_SDK_ROOT'] = util.GetSDKRoot() rtn = subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stderr, cwd=self.root, env=env) if rtn != 0: raise Error("Building %s: failed." % (self.NAME))
def UpdatePatch(self): if self.URL is None: return git_dir = self.GetBuildLocation() if not os.path.exists(git_dir): raise Error('Source directory not found: %s' % git_dir) try: diff = subprocess.check_output( ['git', 'diff', 'upstream', '--no-ext-diff'], cwd=git_dir) except subprocess.CalledProcessError as e: raise Error('error running git in %s: %s' % (git_dir, str(e))) # Drop index lines for a more stable diff. diff = re.sub('\nindex [^\n]+\n', '\n', diff) # Drop binary files, as they don't work anyhow. diff = re.sub( 'diff [^\n]+\n' '(new file [^\n]+\n)?' '(deleted file mode [^\n]+\n)?' 'Binary files [^\n]+ differ\n', '', diff) # Always filter out config.sub changes diff_skip = ['*config.sub'] # Add optional per-port skip list. diff_skip_file = os.path.join(self.root, 'diff_skip.txt') if os.path.exists(diff_skip_file): with open(diff_skip_file) as f: diff_skip += f.read().splitlines() new_diff = '' skipping = False for line in diff.splitlines(): if line.startswith('diff --git a/'): filename = line[len('diff --git a/'):].split()[0] skipping = False for skip in diff_skip: if fnmatch.fnmatch(filename, skip): skipping = True break if not skipping: new_diff += line + '\n' diff = new_diff # Write back out the diff. patch_path = self.GetPatchFile() preexisting = os.path.exists(patch_path) if not diff: if preexisting: Log('removing patch file: %s' % util.RelPath(patch_path)) os.remove(patch_path) else: Log('no patch required: %s' % util.RelPath(git_dir)) return if preexisting: with open(patch_path) as f: if diff == f.read(): Log('patch unchanged: %s' % util.RelPath(patch_path)) return with open(patch_path, 'w') as f: f.write(diff) if preexisting: Log('created patch: %s' % util.RelPath(patch_path)) else: Log('updated patch: %s' % util.RelPath(patch_path))