我正在寻找一种工具,可以批量向某些源文件添加许可证标头,其中一些源文件已经具有标头。是否有工具可以插入标题(如果尚不存在)?
编辑:我故意不标记这个问题的答案,因为答案基本上都是针对特定环境和主观的
#!/bin/bash
for i in *.cc # or whatever other pattern...
do
if ! grep -q Copyright $i
then
cat copyright.txt $i >$i.new && mv $i.new $i
fi
done
这里有一个 Bash 脚本可以解决这个问题,假设您在文件 license.txt 中有许可证头:
文件addlicense.sh:
#!/bin/bash
for x in $*; do
head -$LICENSELEN $x | diff license.txt - || ( ( cat license.txt; echo; cat $x) > /tmp/file;
mv /tmp/file $x )
done
现在在源目录中运行它:
export LICENSELEN=`wc -l license.txt | cut -f1 -d ' '`
find . -type f \(-name \*.cpp -o -name \*.h \) -print0 | xargs -0 ./addlicense.sh
查看 版权标题 RubyGem。它支持扩展名以 php、c、h、cpp、hpp、hh、rb、css、js、html 结尾的文件。它还可以添加和删除标题。
输入“
sudo gem install copyright-header
”安装它
之后,可以做类似的事情:
copyright-header --license GPL3 \
--add-path lib/ \
--copyright-holder 'Dude1 <[email protected]>' \
--copyright-holder 'Dude2 <[email protected]>' \
--copyright-software 'Super Duper' \
--copyright-software-description "A program that makes life easier" \
--copyright-year 2012 \
--copyright-year 2012 \
--word-wrap 80 --output-dir ./
它还支持使用 --license-file 参数的自定义许可证文件。
Python 2解决方案,根据自己的需要进行修改
特点:
excludedir
数组中给出的目录# updates the copyright information for all .cs files
# usage: call recursive_traversal, with the following parameters
# parent directory, old copyright text content, new copyright text content
import os
excludedir = ["..\\Lib"]
def update_source(filename, oldcopyright, copyright):
utfstr = chr(0xef)+chr(0xbb)+chr(0xbf)
fdata = file(filename,"r+").read()
isUTF = False
if (fdata.startswith(utfstr)):
isUTF = True
fdata = fdata[3:]
if (oldcopyright != None):
if (fdata.startswith(oldcopyright)):
fdata = fdata[len(oldcopyright):]
if not (fdata.startswith(copyright)):
print "updating "+filename
fdata = copyright + fdata
if (isUTF):
file(filename,"w").write(utfstr+fdata)
else:
file(filename,"w").write(fdata)
def recursive_traversal(dir, oldcopyright, copyright):
global excludedir
fns = os.listdir(dir)
print "listing "+dir
for fn in fns:
fullfn = os.path.join(dir,fn)
if (fullfn in excludedir):
continue
if (os.path.isdir(fullfn)):
recursive_traversal(fullfn, oldcopyright, copyright)
else:
if (fullfn.endswith(".cs")):
update_source(fullfn, oldcopyright, copyright)
oldcright = file("oldcr.txt","r+").read()
cright = file("copyrightText.txt","r+").read()
recursive_traversal("..", oldcright, cright)
exit()
编辑: 如果您使用 eclipse,有 一个插件
我根据Silver Dragon的回复写了一个简单的python脚本。 我需要一个更灵活的解决方案,所以我想出了这个。 它允许您递归地向目录中的所有文件添加头文件。 您可以选择添加文件名应匹配的正则表达式、目录名称应匹配的正则表达式以及文件中第一行不应匹配的正则表达式。 您可以使用最后一个参数来检查标头是否已包含。
如果文件以 shebang (#!) 开头,此脚本将自动跳过文件中的第一行。这是为了不破坏依赖于此的其他脚本。 如果您不希望出现此行为,则必须在 writeheader 中注释掉 3 行。
这里是:
#!/usr/bin/python
"""
This script attempts to add a header to each file in the given directory
The header will be put the line after a Shebang (#!) if present.
If a line starting with a regular expression 'skip' is present as first line or after the shebang it will ignore that file.
If filename is given only files matchign the filename regex will be considered for adding the license to,
by default this is '*'
usage: python addheader.py headerfile directory [filenameregex [dirregex [skip regex]]]
easy example: add header to all files in this directory:
python addheader.py licenseheader.txt .
harder example adding someone as copyrightholder to all python files in a source directory,exept directories named 'includes' where he isn't added yet:
python addheader.py licenseheader.txt src/ ".*\.py" "^((?!includes).)*$" "#Copyright .* Jens Timmerman*"
where licenseheader.txt contains '#Copyright 2012 Jens Timmerman'
"""
import os
import re
import sys
def writeheader(filename,header,skip=None):
"""
write a header to filename,
skip files where first line after optional shebang matches the skip regex
filename should be the name of the file to write to
header should be a list of strings
skip should be a regex
"""
f = open(filename,"r")
inpt =f.readlines()
f.close()
output = []
#comment out the next 3 lines if you don't wish to preserve shebangs
if len(inpt) > 0 and inpt[0].startswith("#!"):
output.append(inpt[0])
inpt = inpt[1:]
if skip and skip.match(inpt[0]): #skip matches, so skip this file
return
output.extend(header) #add the header
for line in inpt:
output.append(line)
try:
f = open(filename,'w')
f.writelines(output)
f.close()
print "added header to %s" %filename
except IOError,err:
print "something went wrong trying to add header to %s: %s" % (filename,err)
def addheader(directory,header,skipreg,filenamereg,dirregex):
"""
recursively adds a header to all files in a dir
arguments: see module docstring
"""
listing = os.listdir(directory)
print "listing: %s " %listing
#for each file/dir in this dir
for i in listing:
#get the full name, this way subsubdirs with the same name don't get ignored
fullfn = os.path.join(directory,i)
if os.path.isdir(fullfn): #if dir, recursively go in
if (dirregex.match(fullfn)):
print "going into %s" % fullfn
addheader(fullfn, header,skipreg,filenamereg,dirregex)
else:
if (filenamereg.match(fullfn)): #if file matches file regex, write the header
writeheader(fullfn, header,skipreg)
def main(arguments=sys.argv):
"""
main function: parses arguments and calls addheader
"""
##argument parsing
if len(arguments) > 6 or len(arguments) < 3:
sys.stderr.write("Usage: %s headerfile directory [filenameregex [dirregex [skip regex]]]\n" \
"Hint: '.*' is a catch all regex\nHint:'^((?!regexp).)*$' negates a regex\n"%sys.argv[0])
sys.exit(1)
skipreg = None
fileregex = ".*"
dirregex = ".*"
if len(arguments) > 5:
skipreg = re.compile(arguments[5])
if len(arguments) > 3:
fileregex = arguments[3]
if len(arguments) > 4:
dirregex = arguments[4]
#compile regex
fileregex = re.compile(fileregex)
dirregex = re.compile(dirregex)
#read in the headerfile just once
headerfile = open(arguments[1])
header = headerfile.readlines()
headerfile.close()
addheader(arguments[2],header,skipreg,fileregex,dirregex)
#call the main method
main()
对于 Java,您可以使用 Maven 的许可证插件:http://code.google.com/p/maven-license-plugin/
这里是一个简单的仅限 Windows 的 UI 工具,它可以在文件夹中搜索指定类型的所有文件,将您想要的文本添加到顶部(您的许可证文本),然后将结果复制到另一个目录(避免潜在的覆盖问题) )。它也是免费的。需要 .Net 4.0。
我实际上是作者,所以请随意请求修复或新功能......但不承诺交付时间表。 ;)
更多信息:许可证头工具位于Amazify.com
查看许可证添加器。它支持多个代码文件(甚至是自定义文件)并正确处理现有标头。已附带最常见的开源许可证的模板。
这是我在 PHP 中引入的一个用于修改 PHP 文件的方法。我还需要删除旧的许可证信息,因此它首先替换旧文本,然后在打开后立即添加新文本
<?php
class Licenses
{
protected $paths = array();
protected $oldTxt = '/**
* Old license to delete
*/';
protected $newTxt = '/**
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/';
function licensesForDir($path)
{
foreach(glob($path.'/*') as $eachPath)
{
if(is_dir($eachPath))
{
$this->licensesForDir($eachPath);
}
if(preg_match('#\.php#',$eachPath))
{
$this->paths[] = $eachPath;
}
}
}
function exec()
{
$this->licensesForDir('.');
foreach($this->paths as $path)
{
$this->handleFile($path);
}
}
function handleFile($path)
{
$source = file_get_contents($path);
$source = str_replace($this->oldTxt, '', $source);
$source = preg_replace('#\<\?php#',"<?php\n".$this->newTxt,$source,1);
file_put_contents($path,$source);
echo $path."\n";
}
}
$licenses = new Licenses;
$licenses->exec();