向源文件添加许可证头的工具?

我正在寻找一个工具,将批量,添加一个许可证头到一些源文件,其中一些已经有头。是否有一个工具,将插入一个标题,如果它不是已经存在?

编辑: 我故意不标记这个问题的答案,因为答案基本上都是特定于环境和主观的

41204 次浏览

Python 2 solution, modify for your own need

Features:

  • handles UTF headers (important for most IDEs)
  • recursively updates all files in target directory passing given mask (modify the .endswith parameter for the filemask of your language (.c, .java, ..etc)
  • ability to overwrite previous copyright text (provide old copyright parameter to do this)
  • optionally omits directories given in the excludedir array
# 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()
#!/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

Here's a Bash script that'll do the trick, assuming you have the license header in the file license.txt:

File 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

Now run this in your source directory:

export LICENSELEN=`wc -l license.txt | cut -f1 -d ' '`
find . -type f \(-name \*.cpp -o -name \*.h \) -print0 | xargs -0 ./addlicense.sh

For Java you can use Maven's License plugin: http://code.google.com/p/maven-license-plugin/

Here's one I found on the Apache list. Its written in Ruby and seems easy enough to read. You should even be able to call it from rake for extra special niceness. :)

If you still need one, there is a little tool I have written, named SrcHead. You can find it at http://www.solvasoft.nl/downloads.html

Ok here is a simple windows-only UI tool that searches for all files of your specified type in a folder, prepends the text you desire to the top (your license text), and copies the result to another directory (avoiding potential overwrite problems). It's also free. Required .Net 4.0.

I am actually the author, so feel free to request fixes or new features... no promises on delivery schedule though. ;)

more info: License Header tool at Amazify.com

Edit: If you're using eclipse, there's a plugin

I wrote a simple python script based on Silver Dragon's reply. I needed a more flexible solution so I came up with this. It allows you to add a headerfile to all files in a directory, recursively. You can optionally add a regex which the filenames should match, and a regex wich the directory names should match and a regex which the first line in the file shouldn't match. You can use this last argument to check if the header is already included.

This script will automatically skip the first line in a file if this starts with a shebang (#!). This to not break other scripts that rely on this. If you do not wish this behaviour you'll have to comment out 3 lines in writeheader.

here it is:

#!/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()

Check out the copyright-header RubyGem. It supports files with extensions ending in php, c, h, cpp, hpp, hh, rb, css, js, html. It can also add and remove headers.

Install it by typing "sudo gem install copyright-header"

After that, can do something like:

copyright-header --license GPL3 \
--add-path lib/ \
--copyright-holder 'Dude1 <dude1@host.com>' \
--copyright-holder 'Dude2 <dude2@host.com>' \
--copyright-software 'Super Duper' \
--copyright-software-description "A program that makes life easier" \
--copyright-year 2012 \
--copyright-year 2012 \
--word-wrap 80 --output-dir ./

It also supports custom license files using the --license-file argument.

Check out license-adder. It supports multiple code files (even custom ones) and handles existing headers correctly. Comes already with templates for the most common Open Source licenses.

Here is one I rolled in PHP to modify PHP files. I also had old license information to delete so it replaces the old text first, then adds the new text immediately after the opening

<?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();