对于开发项目中,一般存在非常多的第三方依赖,我们往往需要将它们及它们的License列出到NOTICES文件
编写NOTICES总是一件麻烦的事情,对于我开发Avalonia框架的项目来说,一个空的项目可能就会有总共一百多项依赖,我们需要将它们一一收集、分类并编写成NOTICES文件;虽有一些工具可以帮助我们收集依赖,比如 nuget-license,不过它们只是列出,依然需要我们手动分类和收集许可证
nuget-license有一个-d参数,它可以自动去下载许可证,不过这些许可证是来自NuGet的、没有Copyright、且是.html格式的文件,这当然是不能使用的
以目前的情况,我们很难稳定且高效地自动化获取真正的许可证原文,不过,还有一件东西——人
我们可以手动收集许可证并归类,通过程序化读取这些信息并自动生成完整的NOTICES文件,尽管首次收集需要投入更多精力,但是在这一次之后每次编写NOTICES都是如此轻松
总而言之,Notices Generator可以通过nuget-license生成的License Report并结合人手动收集的信息而生成完整的NOTICES;目前我已经为其收集了182个单软件包、17个项目库的信息,应该可以满足基本的Avalonia Cross-Platform项目开发
这是一个简单的Console项目,包括两个内嵌资源Category.json以及ClassInfo.json;
在项目中的很多软件包,它们本质可能都来自同一个库,如Avalonia.Desktop和Avalonia.Android的源代码仓库都是同一个;对于“师出同门”的软件包,我们一般只需列出名字并附带一次许可证原文;
我以是否出自同一个源代码仓库来判断它们是否属于同一个分类(Class),并在Category.json中定义了分类,格式如下
[
{
"Name": "ClassName",
"Packages": [
"Package1",
"Package2"
...
]
}
]其中,ClassName作为该分类的名称,Packages为该分类下的所有包,我建议在每个Class中添加注释("//"键)或Website键补充源代码网址信息,作为分类依据,它就是每个分类的唯一标识符
在ClassInfo.json中定义了每个分类下的信息,格式如下
[
{
"Name": "ClassName",
"Copyrights": ["Copyright1", "Copyright2"],
"Website": "ProjectWebsite",
"LicenseType": "LicenseType",
"License": "OriginalLicenseText",
"Notes": "SomeNote"
}
]其中的Copyrights只需写名字,程序会自动补充Copyright (c)
这样的架构只需要存储一次完整信息,大大节省存储空间和维护成本,虽需使用Linq查找,但对于工具来说它的速度足够快(以目前182个软件包得出的测试结果,运行时间在40ms以下)
程序运行时,先从Report文件中获取包的PackageId,通过Linq在Category中找到与其一致的Package,然后获取ClassName并生成中间文件PackageInfo(默认不保存),格式如下
[
{
"Name": "PackageName",
"Class": "ClassName"
}
]接着通过Linq在ClassInfo中找到此个Class,获取到此类的完整信息,并生成中间文件NoticeInfo(默认不保存),格式如下
[
{
"Name": "ClassName",
"Copyrights": ["Copyright1", "Copyright2"],
"Packages": ["Package1", "Packages2"],
"Website": "ProjectWebsite",
"LicenseType": "LicenseType",
"License": "OriginalLicenseText",
"Notes": "SomeNote"
}
]最终,程序根据NoticeInfo生成Notices文件,目前的Notices文件格式如下:
[FileHeader]
========================================================================
1. [ClassName]
========================================================================
The following packages are part of the [ClassName]:
- [Package1]
- [Package2]
Repository: [Website]
License: [LicenseType]
Copyright (c) [Copyright1]
Copyright (c) [Copyright2]
------------------------------------------------------------------------
[OriginalLicenseText]
------------------------------------------------------------------------
你可以使用命令行来带参启动程序,你应该在Release里下载我们的可执行文件,并将它的目录添加到环境变量中;我这里将AssemblyName设置为了notices-gen,在命令行中输入此命令即可启动程序
Tip
可以通过重命名可执行文件为任何名称以自定义命令,但我不建议你这么做
首先,你应该使用 nuget-license 来生成依赖报告,使用如下命令安装这个工具
dotnet tool install --global nuget-license然后,运行如下命令生成名为report.json的JSON格式Report文件
nuget-license -i YourSolution.sln --include-transitive -o JsonPretty > report.json接着,确保工具目录已在环境变量Path,便可以执行如下的命令
notices-gen -i report.json -o NOTICES.txt-i或--input为输入文件路径,即刚才生成的Report-o或--output为输出文件路径
或者在不带-o参数的情况下,生成结果只会输出到控制台
也可以指定Category和ClassInfo文件而不使用内置
notices-gen -i report.json -o NOTICES.txt -f Category.json -c ClassInfo.json-f或--category为Category文件路径-c或--class-info为ClassInfo文件路径
可以添加--file-header参数为NOTICES添加文件头
notices-gen -i report.json -o NOTICES.txt --file-header "This product includes software developed by third parties.
The following notices and licenses apply to the included components."Important
错误筛查:
由于收集到的程序包有限,我无法保证大家使用的程序包都被此工具收录,工具运行时会输出详细的日志信息,未收录(Undefined)的程序包会显示Warning并在NOTICES末尾列出,所以在每次使用后请检查NOTICES末尾,若发现有列出的程序包,请手动补全信息
另外,若你的项目中包含不是通过NuGet包安装的第三方资源(如字体等),也需自行收集并补充
- Newtonsoft.Json
- Copyright (c) 2007 James Newton-King
- License: MIT
该项目并没有直接引用nuget-license的代码
我希望大家可以协助收集各种程序包的信息(Category.json和ClassInfo.json),并提交一份PR;这是一个以"人"为主的项目,只有前人细心收集软件包信息,后来的人才能更好地享受到工具的便利
至于我个人,我会将我所有使用过的包都添加到其中,并同时尽可能收集更多的.NET开发常用库,如果你发现了包信息错误、或者想要某些包被添加到其中,请提交一份Issue或给我发送邮件
如果你发现了包的信息错误、或希望添加包、或者有任何建议,亦或者是对于此工具有什么问题,都可以在GitHub提交一个Issue或者使用邮件联系我