8 from datetime import datetime
9 from urllib.request import urlretrieve
10 from zipfile import ZipFile
12 NUSPEC_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?>
13 <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
15 <id>{package_name}</id>
16 <authors>{author}</authors>
17 <owners>{owner}</owners>
18 <licenseUrl>{license_url}</licenseUrl>
19 <projectUrl>{project_url}</projectUrl>
20 <iconUrl>{icon_url}</iconUrl>
21 <requireLicenseAcceptance>false</requireLicenseAcceptance>
22 <description>{description}.</description>
23 <copyright>{copyright}</copyright>
25 <version>{version}</version>
27 {dependencies} </dependencies>
34 TARGETS_TEMPLATE = r"""<?xml version="1.0" encoding="utf-8"?>
35 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
36 <Target Name="{package_name}CopyMapConfigs" AfterTargets="AfterBuild">
37 <CreateItem Include="$(MSBuildThisFileDirectory)\{frameworkdir}\*.config">
38 <Output TaskParameter="Include" ItemName="MapConfigs" />
41 <Copy SourceFiles="@(MapConfigs)" DestinationFiles="@(MapConfigs->'$(OutDir)\%(RecursiveDir)%(Filename)%(Extension)')" />
47 def cleanup_args(self):
48 self.nugetdir = os.path.join(self.builddir,
49 self.package_name + 'nupkg')
50 self.frameworkdir = 'net45'
51 self.nuget_build_dir = os.path.join(
52 self.nugetdir, 'build', self.frameworkdir)
53 self.nuget_lib_dir = os.path.join(
54 self.nugetdir, 'lib', self.frameworkdir)
55 self.nuspecfile = os.path.join(
56 self.nugetdir, '%s.nuspec' % self.package_name)
57 self.nugettargets = os.path.join(
58 self.nuget_build_dir, "%s.targets" % self.package_name)
59 self.nuget = shutil.which('nuget')
61 print("Could not find the `nuget` tool, install it and retry!")
64 for d in [self.nugetdir, self.nuget_lib_dir, self.nuget_build_dir]:
65 os.makedirs(d, exist_ok=True)
66 if not self.description:
67 self.description = "%s c# bindings" % self.package_name
68 if not self.copyright:
69 self.copyright = "Copyright %s" % datetime.now().year
71 self.tags = self.package_name
76 res = self.cleanup_args()
82 def add_file(path, target="lib"):
83 f = ' <file src="%s" target="%s"/>\n' % (
84 path, os.path.join(target, os.path.basename(path)))
87 self.dependencies = ''
88 for dependency in self.dependency:
89 _id, version = dependency.split(":")
90 self.dependencies += ' <dependency id="%s" version="%s" />\n' % (
93 for assembly in self.assembly:
94 add_file(assembly, os.path.join('lib', self.frameworkdir))
96 for f in [assembly + '.config', assembly[:-3] + 'pdb']:
98 add_file(f, os.path.join('build', self.frameworkdir))
100 with open(self.nugettargets, 'w') as _:
101 print(TARGETS_TEMPLATE.format(**self.__dict__), file=_)
102 add_file(self.nugettargets, 'build')
104 with open(self.nuspecfile, 'w') as _:
105 print(NUSPEC_TEMPLATE.format(**self.__dict__), file=_)
107 subprocess.check_call([self.nuget, 'pack', self.nuspecfile],
111 class NugetDownloader:
112 def reporthook(self, blocknum, blocksize, totalsize):
113 readsofar = blocknum * blocksize
115 percent = readsofar * 1e2 / totalsize
116 s = "\r%5.1f%% %*d / %d" % (
117 percent, len(str(totalsize)), readsofar, totalsize)
119 if readsofar >= totalsize: # near the end
120 sys.stderr.write("\n")
121 else: # total size is unknown
122 sys.stderr.write("read %d\n" % (readsofar,))
125 url = "https://www.nuget.org/api/v2/package/{nuget_name}/{nuget_version}".format(
127 workdir = os.path.join(self.current_builddir,
128 self.nuget_name, self.nuget_version)
129 os.makedirs(workdir, exist_ok=True)
132 with open(os.path.join(workdir, 'linkline'), 'r') as f:
135 except FileNotFoundError:
137 nugetpath = os.path.join(workdir, self.nuget_name) + '.zip'
138 print("Downloading %s into %s" % (url, nugetpath), file=sys.stderr)
139 urlretrieve(url, nugetpath, self.reporthook)
141 lib_path = os.path.join('lib', self.csharp_version)
142 dll_path = os.path.join(self.nuget_name, self.nuget_version)
143 extract_dir = os.path.join(self.current_builddir, dll_path)
144 os.makedirs(extract_dir, exist_ok=True)
147 print("%s - %s" % (self.builddir, extract_dir), file=sys.stderr)
148 with ZipFile(nugetpath) as zip:
149 for f in zip.infolist():
150 if f.filename.startswith(lib_path):
151 zip.extract(f, path=extract_dir)
152 if f.filename.endswith('.dll'):
153 linkline += ' -r:' + \
154 os.path.relpath(os.path.join(
155 extract_dir, f.filename), self.builddir)
157 with open(os.path.join(workdir, 'linkline'), 'w') as f:
158 print(linkline.strip(), file=f)
160 print(linkline.strip())
163 if __name__ == "__main__":
164 if "get" not in sys.argv:
165 parser = argparse.ArgumentParser()
166 parser.add_argument('--builddir')
167 parser.add_argument('--package-name')
168 parser.add_argument('--author', default=getpass.getuser())
169 parser.add_argument('--owner', default=getpass.getuser())
170 parser.add_argument('--native', action='append', default=[])
171 parser.add_argument('--assembly', action='append', default=[])
172 parser.add_argument('--out')
173 parser.add_argument('--description')
174 parser.add_argument('--copyright')
175 parser.add_argument('--version')
176 parser.add_argument('--icon-url', default='')
177 parser.add_argument('--project-url', default='')
178 parser.add_argument('--license-url', default='')
179 parser.add_argument('--tags', default='')
180 parser.add_argument('--dependency', default=[], action='append')
182 runner = Nugetifier()
184 sys.argv.remove('get')
185 parser = argparse.ArgumentParser()
186 parser.add_argument('--builddir')
187 parser.add_argument('--current-builddir')
188 parser.add_argument('--nuget-name')
189 parser.add_argument('--nuget-version')
190 parser.add_argument('--csharp-version')
192 runner = NugetDownloader()
194 options = parser.parse_args(namespace=runner)