| #!/usr/bin/python3 | |
| import argparse | |
| import getpass | |
| import os | |
| import sys | |
| import shutil | |
| import subprocess | |
| from datetime import datetime | |
| from urllib.request import urlretrieve | |
| from zipfile import ZipFile | |
| NUSPEC_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?> | |
| <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> | |
| <metadata> | |
| <id>{package_name}</id> | |
| <authors>{author}</authors> | |
| <owners>{owner}</owners> | |
| <licenseUrl>{license_url}</licenseUrl> | |
| <projectUrl>{project_url}</projectUrl> | |
| <iconUrl>{icon_url}</iconUrl> | |
| <requireLicenseAcceptance>false</requireLicenseAcceptance> | |
| <description>{description}.</description> | |
| <copyright>{copyright}</copyright> | |
| <tags>{tags}</tags> | |
| <version>{version}</version> | |
| <dependencies> | |
| {dependencies} </dependencies> | |
| </metadata> | |
| <files> | |
| {files} </files> | |
| </package> | |
| """ | |
| TARGETS_TEMPLATE = r"""<?xml version="1.0" encoding="utf-8"?> | |
| <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |
| <Target Name="{package_name}CopyMapConfigs" AfterTargets="AfterBuild"> | |
| <CreateItem Include="$(MSBuildThisFileDirectory)\{frameworkdir}\*.config"> | |
| <Output TaskParameter="Include" ItemName="MapConfigs" /> | |
| </CreateItem> | |
| <Copy SourceFiles="@(MapConfigs)" DestinationFiles="@(MapConfigs->'$(OutDir)\%(RecursiveDir)%(Filename)%(Extension)')" /> | |
| </Target> | |
| </Project>""" | |
| class Nugetifier: | |
| def cleanup_args(self): | |
| self.nugetdir = os.path.join(self.builddir, | |
| self.package_name + 'nupkg') | |
| self.frameworkdir = 'net45' | |
| self.nuget_build_dir = os.path.join( | |
| self.nugetdir, 'build', self.frameworkdir) | |
| self.nuget_lib_dir = os.path.join( | |
| self.nugetdir, 'lib', self.frameworkdir) | |
| self.nuspecfile = os.path.join( | |
| self.nugetdir, '%s.nuspec' % self.package_name) | |
| self.nugettargets = os.path.join( | |
| self.nuget_build_dir, "%s.targets" % self.package_name) | |
| self.nuget = shutil.which('nuget') | |
| if not self.nuget: | |
| print("Could not find the `nuget` tool, install it and retry!") | |
| return -1 | |
| for d in [self.nugetdir, self.nuget_lib_dir, self.nuget_build_dir]: | |
| os.makedirs(d, exist_ok=True) | |
| if not self.description: | |
| self.description = "%s c# bindings" % self.package_name | |
| if not self.copyright: | |
| self.copyright = "Copyright %s" % datetime.now().year | |
| if not self.tags: | |
| self.tags = self.package_name | |
| return 0 | |
| def run(self): | |
| res = self.cleanup_args() | |
| if res: | |
| return res | |
| self.files = '' | |
| def add_file(path, target="lib"): | |
| f = ' <file src="%s" target="%s"/>\n' % ( | |
| path, os.path.join(target, os.path.basename(path))) | |
| self.files += f | |
| self.dependencies = '' | |
| for dependency in self.dependency: | |
| _id, version = dependency.split(":") | |
| self.dependencies += ' <dependency id="%s" version="%s" />\n' % ( | |
| _id, version) | |
| for assembly in self.assembly: | |
| add_file(assembly, os.path.join('lib', self.frameworkdir)) | |
| for f in [assembly + '.config', assembly[:-3] + 'pdb']: | |
| if os.path.exists(f): | |
| add_file(f, os.path.join('build', self.frameworkdir)) | |
| with open(self.nugettargets, 'w') as _: | |
| print(TARGETS_TEMPLATE.format(**self.__dict__), file=_) | |
| add_file(self.nugettargets, 'build') | |
| with open(self.nuspecfile, 'w') as _: | |
| print(NUSPEC_TEMPLATE.format(**self.__dict__), file=_) | |
| subprocess.check_call([self.nuget, 'pack', self.nuspecfile], | |
| cwd=self.builddir) | |
| class NugetDownloader: | |
| def reporthook(self, blocknum, blocksize, totalsize): | |
| readsofar = blocknum * blocksize | |
| if totalsize > 0: | |
| percent = readsofar * 1e2 / totalsize | |
| s = "\r%5.1f%% %*d / %d" % ( | |
| percent, len(str(totalsize)), readsofar, totalsize) | |
| sys.stderr.write(s) | |
| if readsofar >= totalsize: # near the end | |
| sys.stderr.write("\n") | |
| else: # total size is unknown | |
| sys.stderr.write("read %d\n" % (readsofar,)) | |
| def run(self): | |
| url = "https://www.nuget.org/api/v2/package/{nuget_name}/{nuget_version}".format( | |
| **self.__dict__) | |
| workdir = os.path.join(self.current_builddir, | |
| self.nuget_name, self.nuget_version) | |
| os.makedirs(workdir, exist_ok=True) | |
| try: | |
| with open(os.path.join(workdir, 'linkline'), 'r') as f: | |
| print(f.read()) | |
| return | |
| except FileNotFoundError: | |
| pass | |
| nugetpath = os.path.join(workdir, self.nuget_name) + '.zip' | |
| print("Downloading %s into %s" % (url, nugetpath), file=sys.stderr) | |
| urlretrieve(url, nugetpath, self.reporthook) | |
| lib_path = os.path.join('lib', self.csharp_version) | |
| dll_path = os.path.join(self.nuget_name, self.nuget_version) | |
| extract_dir = os.path.join(self.current_builddir, dll_path) | |
| os.makedirs(extract_dir, exist_ok=True) | |
| linkline = '' | |
| print("%s - %s" % (self.builddir, extract_dir), file=sys.stderr) | |
| with ZipFile(nugetpath) as zip: | |
| for f in zip.infolist(): | |
| if f.filename.startswith(lib_path): | |
| zip.extract(f, path=extract_dir) | |
| if f.filename.endswith('.dll'): | |
| linkline += ' -r:' + \ | |
| os.path.relpath(os.path.join( | |
| extract_dir, f.filename), self.builddir) | |
| with open(os.path.join(workdir, 'linkline'), 'w') as f: | |
| print(linkline.strip(), file=f) | |
| print(linkline.strip()) | |
| if __name__ == "__main__": | |
| if "get" not in sys.argv: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('--builddir') | |
| parser.add_argument('--package-name') | |
| parser.add_argument('--author', default=getpass.getuser()) | |
| parser.add_argument('--owner', default=getpass.getuser()) | |
| parser.add_argument('--native', action='append', default=[]) | |
| parser.add_argument('--assembly', action='append', default=[]) | |
| parser.add_argument('--out') | |
| parser.add_argument('--description') | |
| parser.add_argument('--copyright') | |
| parser.add_argument('--version') | |
| parser.add_argument('--icon-url', default='') | |
| parser.add_argument('--project-url', default='') | |
| parser.add_argument('--license-url', default='') | |
| parser.add_argument('--tags', default='') | |
| parser.add_argument('--dependency', default=[], action='append') | |
| runner = Nugetifier() | |
| else: | |
| sys.argv.remove('get') | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('--builddir') | |
| parser.add_argument('--current-builddir') | |
| parser.add_argument('--nuget-name') | |
| parser.add_argument('--nuget-version') | |
| parser.add_argument('--csharp-version') | |
| runner = NugetDownloader() | |
| options = parser.parse_args(namespace=runner) | |
| exit(runner.run()) |