用于向源文件添加许可证标头的工具?[关闭]


89

我正在寻找一种工具,该工具将向大量源文件添加许可证标头,其中一些源文件已经具有标头。如果没有标题,有没有可以插入标题的工具?

编辑:我故意不标记此问题的答案,因为答案基本上都是针对特定环境且主观的


5
“我故意不标记此问题的答案,因为答案基本上都是针对特定环境且是主观的”您是否在寻找与环境无关的解决方案,例如伪代码?如果没有,请告诉我们您使用的环境。
jrummell

1
jrummell:不,不是在寻找与环境无关的解决方案。正在寻找我所在的多环境团队可以使用的东西。
亚历克斯·莱曼

可以让您执行此操作的Windows UI应用程序是否可以接受?
布雷迪·莫里茨

@boomhauer我正在寻找Windows UI应用程序。你知道吗
Jus12 2011年

我在下面添加了一个新的答案,它应该做到这一点。
布雷迪·莫里茨

Answers:


61
#!/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

1
对于“ $ @”中的我来说是一个不错的选择。如果您的VCS系统需要结帐,您也可以通过结帐来发挥创造力。
乔纳森·勒夫勒

10
-1,您应该引用"$i"
Aleks-Daniel Jakimenko-A。

我猜想这在递归子目录中不起作用:-(
knocte

2
@knocte替换为for循环以for i in $(find /folder -name '*.cc');在子目录上运行脚本
Joyce

16

Python解决方案,根据您的需要进行修改

特征:

  • 处理UTF标头(对于大多数IDE都很重要)
  • 通过给定的掩码递归地更新目标目录中的所有文件(修改您语言(.c,.java,.. etc等)的文件掩码的.endswith参数
  • 能够覆盖以前的版权文本(为此提供旧的版权参数)
  • 可以选择省略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()

6
提及您的脚本在python中可能不会有任何伤害。
达娜(Dana),

16

查看版权标题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 <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 ./

它还使用--license-file参数支持自定义许可证文件。


这很棒,除了它不会删除自定义的现有标题:(
pgpb.padilla 2014年

3
如果为它们创建模板,则可以删除它们。将模板作为参数传递给带有参数的脚本--license-file,并使用该--remove-path标志从所有文件中删除该确切的标头。基本上,头的类型很多,创建一个可靠地删除它们的算法是很重要的。
Erik Osterman

1
我们最近添加了一个问题,Dockerfile因此安装繁琐的红宝石依赖关系不再是问题
Erik Osterman

15

这是一个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  

1
如果文件名包含数字,则sed表达式将无法正常工作。相反,请考虑使用cut -f1 -d ' '
schweerelos

1
@Rosenfield导出语句中缺少右引号。
Talespin_Kit 2011年

为什么在find命令中需要括号?它对我来说失败了
knocte

13

编辑:如果您使用的是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()

3
插件的链接
断开


在编写自己的python软件包版本之前,我无法彻底使用Google。我可能会借鉴您的解决方案以进行将来的改进。github.com/zkurtz/license_proliferator
zkurtz


11

好的,这是一个仅用于Windows的简单UI工具,它可以在文件夹中搜索指定类型的所有文件,将所需的文本放在顶部(您的许可证文本),然后将结果复制到另一个目录(避免潜在的覆盖问题) 。它也是免费的。必需的.Net 4.0。

我实际上是作者,因此随时可以请求修复或新功能。;)

更多信息:许可证标头工具Amazify.com


此外,我也希望对此表示任何反馈,谢谢
Brady Moritz

1
我真的很喜欢该软件,但是需要一个宏来将文件名输入标头。Allso很高兴显示要编辑的文件列表,并带有排除文件的选项。(:
hs2d 2012年

谢谢,宏和排除列表是一​​个好主意
布雷迪·莫里茨

您的链接已过期。这不是可以从网站下载或者它
valijon

谢谢,我将它修理好
Brady Moritz


4

这是我使用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();

3

这是我在Apache列表中找到的一个。它是用Ruby编写的,似乎很容易阅读。您甚至应该可以从rake调用它,以获得额外的特殊乐趣。:)


1

如果您仍然需要一个,我已经编写了一个名为SrcHead的小工具。您可以在http://www.solvasoft.nl/downloads.html上找到它


3
在下载页面上:“它是为Windows编写的,需要.NET Framework 2.0才能运行。”
里卡多·穆里

添加C / C ++样式标题和Unicode BOM。含义:内容header.txt与前面加上//在每一行,并与统一BOM的第一行开始。
koppor

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.