¿Herramienta para agregar encabezados de licencia a archivos de origen? [cerrado]

89

Estoy buscando una herramienta que, a granel, agregue un encabezado de licencia a algunos archivos fuente, algunos de los cuales ya tienen el encabezado. ¿Existe alguna herramienta que inserte un encabezado, si aún no está presente?

Editar: intencionalmente no estoy marcando una respuesta a esta pregunta, ya que las respuestas son básicamente todas subjetivas y específicas del entorno

Alex Lyman
fuente
5
"No estoy marcando intencionalmente una respuesta a esta pregunta, ya que las respuestas son básicamente todas específicas del entorno y subjetivas" ¿Está buscando una solución independiente del entorno, como un pseudocódigo? Si no es así, háganos saber en qué entorno está trabajando.
jrummell
1
jrummell: No, no busco una solución independiente del medio ambiente. Estaba buscando cosas que pudiera utilizar un equipo de entornos múltiples en el que estaba.
Alex Lyman
¿Sería una respuesta aceptable una aplicación de interfaz de usuario de Windows que le permita hacer esto?
Brady Moritz
@boomhauer Estoy buscando una aplicación de interfaz de usuario de Windows. ¿Sabes de alguno?
Jus12
Agregué una nueva respuesta a continuación, debería hacer exactamente esto.
Brady Moritz

Respuestas:

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
Tim
fuente
1
porque i en "$ @" es una muy buena elección. También puede ser ingenioso con los pagos si su sistema VCS los necesita.
Jonathan Leffler
10
-1, deberías citar"$i"
Aleks-Daniel Jakimenko-A.
Supongo que esto no funciona en subdirectorios de forma recursiva :-(
knocte
2
@knocte Reemplace el bucle for con esto for i in $(find /folder -name '*.cc');para ejecutar el script en subdirectorios
Joyce
16

Solución de Python, modifíquela según sus propias necesidades

caracteristicas:

  • maneja encabezados UTF (importante para la mayoría de IDE)
  • actualiza de forma recursiva todos los archivos en el directorio de destino pasando la máscara dada (modifique el parámetro .endswith para la máscara de archivo de su idioma (.c, .java, ..etc)
  • capacidad de sobrescribir el texto de derechos de autor anterior (proporcione el parámetro de derechos de autor antiguo para hacer esto)
  • opcionalmente omite los directorios dados en la matriz excluida

-

# 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()
Dragón plateado
fuente
6
Probablemente no estaría de más mencionar que su script está en Python.
Dana
16

Echa un vistazo al encabezado de copyright RubyGem. Admite archivos con extensiones que terminan en php, c, h, cpp, hpp, hh, rb, css, js, html. También puede agregar y eliminar encabezados.

Instálelo escribiendo " sudo gem install copyright-header"

Después de eso, puedes hacer algo como:

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 ./

También admite archivos de licencia personalizados mediante el argumento --license-file.

Erik Osterman
fuente
Esto es genial, excepto que no elimina los encabezados personalizados existentes :(
pgpb.padilla
3
Puede eliminar los encabezados existentes si crea una plantilla para ellos. Pase la plantilla como argumento al script con el --license-fileargumento y use la --remove-pathbandera para quitar ese encabezado exacto de todos los archivos. Básicamente, hay tantos tipos diferentes de encabezados que crear un algoritmo para eliminarlos de manera confiable no es trivial.
Erik Osterman
1
Recientemente agregamos una Dockerfileinstalación de dependencias ruby ​​onerosas ya no es un problema
Erik Osterman
15

Aquí hay un script de Bash que hará el truco, suponiendo que tenga el encabezado de la licencia en el archivo license.txt:

Archivo 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  

Ahora ejecute esto en su directorio fuente:

export LICENSELEN=`wc -l license.txt | cut -f1 -d ' '`  
find . -type f \(-name \*.cpp -o -name \*.h \) -print0 | xargs -0 ./addlicense.sh  
Adam Rosenfield
fuente
1
La expresión sed no funcionará bien si el nombre del archivo contiene dígitos. En su lugar, considere usarcut -f1 -d ' '
schweerelos
1
@Rosenfield La comilla simple de cierre se omite en la declaración de exportación.
Talespin_Kit
¿Por qué necesita el paréntesis en el comando de búsqueda? Falló para mí
Knocte
13

Editar: si está usando eclipse, hay un complemento

Escribí un script de Python simple basado en la respuesta de Silver Dragon. Necesitaba una solución más flexible, así que se me ocurrió esto. Le permite agregar un archivo de encabezado a todos los archivos en un directorio, de forma recursiva. Opcionalmente, puede agregar una expresión regular con la que los nombres de archivo deben coincidir, y una expresión regular con la que deben coincidir los nombres de directorio y una expresión regular con la que la primera línea del archivo no debe coincidir. Puede utilizar este último argumento para comprobar si el encabezado ya está incluido.

Este script omitirá automáticamente la primera línea de un archivo si comienza con un shebang (#!). Esto para no romper otros scripts que se basan en esto. Si no desea este comportamiento, tendrá que comentar 3 líneas en writeheader.

aquí está:

#!/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()
Jens Timmerman
fuente
3
Enlace roto para el complemento
mjaggard
Creo que esto podría ser: wiki.eclipse.org/Development_Resources/…
mbdevpl
No pude buscar en Google antes de escribir mi propia versión de paquete de Python de esto. Probablemente me basaré en su solución para futuras mejoras. github.com/zkurtz/license_proliferator
zkurtz
11

Ok, aquí hay una sencilla herramienta de interfaz de usuario solo para Windows que busca todos los archivos del tipo especificado en una carpeta, antepone el texto que desea al principio (el texto de su licencia) y copia el resultado en otro directorio (evitando posibles problemas de sobrescritura) . También es gratis. Se requiere .Net 4.0.

De hecho, soy el autor, así que siéntase libre de solicitar arreglos o nuevas funciones ... sin embargo, no hay promesas sobre el calendario de entrega. ;)

más información: Herramienta de encabezado de licencia en Amazify.com

Brady Moritz
fuente
también, agradecería cualquier comentario sobre esto, gracias
Brady Moritz
1
Realmente me gusta el software, pero se necesita una macro para ingresar el nombre del archivo en el encabezado. También sería bueno mostrar la lista de archivos a editar con una opción para excluir archivos. (:
hs2d
Gracias, la lista de macros y exclusiones es una gran idea
Brady Moritz
Su enlace ha caducado. Tampoco es posible descargarlo desde el sitio
valijon
Gracias, lo repararé
Brady Moritz
5

Consulte el sumador de licencias. Admite varios archivos de código (incluso personalizados) y maneja correctamente los encabezados existentes. Viene ya con plantillas para las licencias de código abierto más comunes.

Peter Pratscher
fuente
1
Gracias por esto, ¿a qué license-adderte refieres exactamente? Encontré License-Adder - Aplicación .NET gratuita - Alojamiento de proyectos de Google y License-Adder · Script Python simple · GitHub
sdaau
GitHub ahora encuentra: github.com/sanandrea/License-Adder
koppor
4

Aquí hay uno que rodé en PHP para modificar archivos PHP. También tenía información de licencia antigua para eliminar, por lo que primero reemplaza el texto anterior, luego agrega el nuevo texto inmediatamente después de la apertura

<?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();
Josh Ribakoff
fuente
3

Aquí hay uno que encontré en la lista de Apache. Está escrito en Ruby y parece bastante fácil de leer. Incluso deberías poder llamarlo desde el rastrillo para una bondad especial adicional. :)

Richard Hurt
fuente
1

Si aún lo necesita, hay una pequeña herramienta que he escrito, llamada SrcHead . Puede encontrarlo en http://www.solvasoft.nl/downloads.html


fuente
3
Desde la página de descarga: "Está escrito para Windows y necesita .NET Framework 2.0 para funcionar".
Riccardo Murri
Agrega encabezados de estilo C / C ++ y una lista de materiales Unicode. Significado: el contenido de header.txtse antepone con //en cada línea y la primera línea comienza con la lista de materiales Unicode.
koppor