Инструмент для добавления заголовков лицензий в исходные файлы? [закрыто]

89

Я ищу инструмент, который будет массово добавлять заголовок лицензии к некоторым исходным файлам, некоторые из которых уже имеют заголовок. Есть ли инструмент, который вставит заголовок, если он еще не присутствует?

Изменить: я намеренно не отмечаю ответ на этот вопрос, поскольку ответы в основном зависят от среды и субъективны.

Алекс Лайман
источник
5
«Я намеренно не отмечаю ответ на этот вопрос, поскольку ответы в основном зависят от среды и субъективны». Вы ищете решение, не зависящее от среды, например псевдокод? Если нет, сообщите нам, с какой средой вы работаете.
jrummell
1
jrummell: Нет, я не ищу решения, не зависящего от окружающей среды. Искал вещи, которые могла бы использовать моя команда, работающая в разных средах.
Alex Lyman
Будет ли приемлемым ответом приложение Windows UI, которое позволит вам это сделать?
Брэди Мориц
@boomhauer Я ищу приложение для Windows UI. Вы что-нибудь знаете?
Jus12
Я добавил новый ответ ниже, он должен делать именно это.
Брэди Мориц

Ответы:

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
for i in "$ @" - довольно хороший выбор. Вы также можете проявить изобретательность с кассами, если они нужны вашей системе VCS.
Джонатан Леффлер,
10
-1, следует процитировать"$i"
Алекс-Даниил Якименко-А.
Я думаю, это не работает рекурсивно в подкаталогах :-(
knocte
2
@knocte Замените цикл for на это, for i in $(find /folder -name '*.cc');чтобы запустить скрипт в подкаталогах
Джойс
16

Решение Python, измените под свои нужды

Особенности:

  • обрабатывает заголовки UTF (важно для большинства IDE)
  • рекурсивно обновляет все файлы в целевом каталоге, передавая заданную маску (измените параметр .endswith для файловой маски вашего языка (.c, .java, ..etc)
  • возможность перезаписать предыдущий текст об авторских правах (для этого укажите старый параметр авторских прав)
  • необязательно исключает каталоги, указанные в массиве 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.
Дана
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
3
Вы можете удалить существующие заголовки, если создадите для них шаблон. Передайте шаблон в качестве аргумента сценарию с --license-fileаргументом и используйте --remove-pathфлаг, чтобы удалить этот точный заголовок из всех файлов. По сути, существует так много разных типов заголовков, что создание алгоритма для их надежного удаления нетривиально.
Эрик Остерман
1
Недавно мы добавили, Dockerfileчто установка обременительных рубиновых зависимостей больше не проблема,
Эрик Остерман,
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
зачем вам скобка в команде find? это не удалось для меня
knocte
13

Изменить: если вы используете eclipse, есть плагин

Я написал простой скрипт на Python, основанный на ответе Silver Dragon. Мне нужно было более гибкое решение, поэтому я придумал это. Он позволяет вам рекурсивно добавлять заголовочный файл ко всем файлам в каталоге. При желании вы можете добавить регулярное выражение, которому должны соответствовать имена файлов, и регулярное выражение, которому должны соответствовать имена каталогов, и регулярное выражение, которому не должна соответствовать первая строка в файле. Вы можете использовать этот последний аргумент, чтобы проверить, включен ли уже заголовок.

Этот сценарий автоматически пропустит первую строку в файле, если она начинается с shebang (#!). Это сделано, чтобы не нарушить работу других скриптов, которые на это полагаются. Если вы не хотите этого поведения, вам придется закомментировать 3 строки в writeheader.

вот:

#!/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
Неработающая
Думаю, это могло быть так: wiki.eclipse.org/Development_Resources/…
mbdevpl 01
Мне не удалось полностью погуглить, прежде чем писать мою собственную версию пакета Python this. Скорее всего, я воспользуюсь вашим решением для будущих улучшений. github.com/zkurtz/license_proliferator
zkurtz
11

Хорошо, вот простой инструмент пользовательского интерфейса только для Windows, который ищет все файлы указанного типа в папке, добавляет желаемый текст в начало (текст вашей лицензии) и копирует результат в другой каталог (избегая потенциальных проблем с перезаписью) . Это тоже бесплатно. Требуется .Net 4.0.

На самом деле я являюсь автором, поэтому не стесняйтесь запрашивать исправления или новые функции ... однако никаких обещаний по графику доставки нет. ;)

дополнительная информация: Инструмент заголовка лицензии на Amazify.com

Брэди Мориц
источник
Кроме того, я был бы признателен за любые отзывы об этом, спасибо
Брэди Мориц
1
Мне очень нравится программа, но для ввода имени файла в заголовок нужен макрос. Allso было бы неплохо показать список файлов для редактирования с возможностью исключения файлов. (:
hs2d
Спасибо, макрос и список исключений - отличная идея
Брэди Мориц
Срок действия вашей ссылки истек. С сайта тоже не
получается
Спасибо, я отремонтирую
Брэди Мориц
5

Ознакомьтесь с лицензионным сумматором. Он поддерживает несколько файлов кода (даже пользовательских) и правильно обрабатывает существующие заголовки. Поставляется уже с шаблонами для наиболее распространенных лицензий с открытым исходным кодом.

Питер Пратчер
источник
1
Спасибо за это, о чем license-adderвы конкретно имеете в виду? Я нашел сумматор лицензий - бесплатное приложение .NET - хостинг проектов Google и
добавитель
GitHub теперь находит: github.com/sanandrea/License-Adder
koppor
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 и кажется достаточно легким для чтения. Вы даже должны иметь возможность звонить с рейка для особой аккуратности. :)

Ричард Хёрт
источник
1

Если он вам все еще нужен, я написал небольшой инструмент под названием SrcHead . Вы можете найти его на http://www.solvasoft.nl/downloads.html.


источник
3
На странице загрузки: «Он написан для Windows и для работы требует .NET Framework 2.0».
Риккардо Мурри
Добавляет заголовки стиля C / C ++ и спецификацию Unicode. Значение: содержимое header.txtдобавляется //к каждой строке, а первая строка начинается с спецификации Unicode.
koppor