¿Cómo puedo administrar mejor las versiones de código fuente abierto del código de investigación confidencial de mi empresa?

13

Mi compañía (llamémosle Acme Technology) tiene una biblioteca de aproximadamente mil archivos de origen que originalmente provino de su grupo de investigación Acme Labs, que se incubó en un grupo de desarrollo durante un par de años, y más recientemente se ha proporcionado a unos pocos de clientes bajo no divulgación. Acme se está preparando para liberar tal vez el 75% del código a la comunidad de código abierto. El otro 25% se lanzaría más adelante, pero por ahora, o no está listo para el uso del cliente o contiene código relacionado con las innovaciones futuras que necesitan para mantenerse fuera del alcance de los competidores.

El código está formateado actualmente con #ifdefs que permite que la misma base de código funcione con las plataformas de preproducción que estarán disponibles para los investigadores universitarios y para una gama mucho más amplia de clientes comerciales una vez que sea de código abierto, mientras que Al mismo tiempo, está disponible para la experimentación y creación de prototipos, y para las pruebas de compatibilidad con la plataforma futura. Mantener una base de código única se considera esencial para la economía (y la cordura) de mi grupo, que tendría dificultades para mantener dos copias en paralelo.

Los archivos en nuestra base actual se parecen a esto:

> // Copyright 2012 (C) Acme Technology, All Rights Reserved.
> // Very large, often varied and restrictive copyright license in English and French,
> // sometimes also embedded in make files and shell scripts with varied 
> // comment styles. 
> 
> 
>   ... Usual header stuff...
>
> void initTechnologyLibrary() {
>     nuiInterface(on);
> #ifdef  UNDER_RESEARCH
>     holographicVisualization(on);
> #endif
> }

Y nos gustaría convertirlos en algo como:

> // GPL Copyright (C) Acme Technology Labs 2012, Some rights reserved.
> // Acme appreciates your interest in its technology, please contact [email protected] 
> // for technical support, and www.acme.com/emergingTech for updates and RSS feed.
> 
>   ... Usual header stuff...
>
> void initTechnologyLibrary() {
>     nuiInterface(on);
> }

¿Existe una herramienta, una biblioteca de análisis o un script popular que pueda reemplazar los derechos de autor y eliminar no solo #ifdefs, sino variaciones como #if definido (UNDER_RESEARCH), etc.?

El código está actualmente en Git y probablemente se alojaría en algún lugar que use Git. ¿Habría una manera de vincular los repositorios de manera segura para que podamos reintegrar de manera eficiente nuestras mejoras con las versiones de código abierto? El consejo sobre otras trampas es bienvenido.

    
pregunta DeveloperDon 07.11.2012 - 06:27

5 respuestas

6

Parece que no sería demasiado difícil escribir un script para analizar los preprocesadores, compararlos con una lista de constantes definidas ( UNDER_RESEARCH , FUTURE_DEVELOPMENT , etc.) y, si la directiva puede evaluarse a falso dado lo que está definido, elimine todo hasta el siguiente #endif .

En Python, haría algo como,

import os

src_dir = 'src/'
switches = {'UNDER_RESEARCH': True, 'OPEN_SOURCE': False}
new_header = """// GPL Copyright (C) Acme Technology Labs 2012, Some rights reserved.
// Acme appreciates your interest in its technology, please contact [email protected] 
// for technical support, and www.acme.com/emergingTech for updates and RSS feed.
"""

filenames = os.listdir(src_dir)
for fn in filenames:
    contents = open(src_dir+fn, 'r').read().split('\n')
    outfile = open(src_dir+fn+'-open-source', 'w')
    in_header = True
    skipping = False
    for line in contents:
        # remove original header
        if in_header and (line.strip() == "" or line.strip().startswith('//')):
            continue
        elif in_header:
            in_header = False
            outfile.write(new_header)

        # skip between ifdef directives
        if skipping:
            if line.strip() == "#endif":
                skipping = False
            continue
        # check
        if line.strip().startswith("#ifdef"):
            # parse #ifdef (maybe should be more elegant)
            # this assumes a form of "#ifdef SWITCH" and nothing else
            if line.strip().split()[1] in switches.keys():
                skipping = True
                continue

        # checking for other forms of directives is left as an exercise

        # got this far, nothing special - echo the line
        outfile.write(line)
        outfile.write('\n')

Estoy seguro de que hay formas más elegantes de hacerlo, pero esto es rápido y sucio y parece que hace el trabajo.

    
respondido por el WasabiFlux 08.11.2012 - 02:54
3

Estaba pensando en pasar su código a través del preprocesador para expandir solo las macros, y así generar solo la parte interesante en el #ifdef s.

Algo como esto debería funcionar:

gcc -E yourfile.c

Pero:

  • Perderás todos los comentarios. Puedes usar -CC para (mantenerlas), pero luego tendrás que quitarte el antiguo aviso de copyright
  • #include s también se expanden, por lo que terminará con un archivo grande que contiene todo el contenido de los archivos de encabezado incluidos
  • Perderás macros "estándar".

Puede haber una manera de limitar qué macros se expanden; Sin embargo, mi sugerencia aquí es dividir las cosas, en lugar de hacer un procesamiento (potencialmente peligroso) en los archivos (por cierto, ¿cómo planearía mantenerlos después? Ej., reintroducir el código de la versión de código abierto en su código cerrado). / p>

Es decir, intente colocar el código que desea abrir en las bibliotecas externas tanto como sea posible, luego utilícelos como lo haría con cualquier otra biblioteca, integrándose con otras bibliotecas de código cerrado "personalizadas".

Al principio puede llevar un poco más de tiempo averiguar cómo reestructurar las cosas, pero definitivamente es la forma correcta de lograr esto.

    
respondido por el redShadow 08.11.2012 - 03:26
2

Tengo una solución pero requerirá un poco de trabajo

pypreprocessor es una biblioteca que proporciona un preprocesador de estilo c puro para python que También se puede utilizar como GPP (Pre-procesador de propósito general) para otros tipos de código fuente.

Aquí hay un ejemplo básico:

from pypreprocessor import pypreprocessor

pypreprocessor.input = 'input_file.c'
pypreprocessor.output = 'output_file.c'
pypreprocessor.removeMeta = True
pypreprocessor.parse()

El preprocesador es extremadamente simple. Hace un pase a través de la fuente y comenta condicionalmente la fuente en función de lo que está definido.

Defines se puede establecer a través de las declaraciones #define en la fuente o configurándolas en la lista pypreprocessor.defines.

La configuración de los parámetros de entrada / salida le permite definir explícitamente qué archivos se abren / cierran para que se pueda configurar un solo preprocesador para procesar por lotes una gran cantidad de archivos, si lo desea.

Al establecer el parámetro removeMeta en True, el preprocesador debería extraer automáticamente todas y cada una de las declaraciones del preprocesador dejando solo el código posprocesado.

Nota: por lo general, esto no tendría que configurarse explícitamente porque Python eliminó el código comentado automáticamente durante la compilación al código de bytes.

Sólo veo un caso de borde. Debido a que está buscando preprocesar la fuente C, es posible que desee configurar las definiciones del procesador explícitamente (es decir, a través de pypreprocessor.defines) y decirle que ignore las declaraciones #define en la fuente. Eso debería evitar que elimine accidentalmente cualquier constante que pueda usar en el código fuente de su proyecto. Actualmente no hay ningún parámetro para configurar esta funcionalidad, pero sería trivial agregarlo.

Aquí hay un ejemplo trivial:

from pypreprocessor import pypreprocessor

# run the script in 'production' mode
if 'commercial' in sys.argv:
    pypreprocessor.defines.append('commercial')

if 'open' in sys.argv:
    pypreprocessor.defines.append('open')

pypreprocessor.removeMeta = True
pypreprocessor.parse()

Luego, la fuente:

#ifdef commercial
// Copyright 2012 (C) Acme Technology, All Rights Reserved.
// Very large, often varied and restrictive copyright license in English and French,
// sometimes also embedded in make files and shell scripts with varied 
// comment styles.
#ifdef open
// GPL Copyright (C) Acme Technology Labs 2012, Some rights reserved.
// Acme appreciates your interest in its technology, please contact [email protected] 
// for technical support, and www.acme.com/emergingTech for updates and RSS feed.
#endif

Nota: Obviamente, deberás encontrar una forma de configurar los archivos de entrada / salida, pero eso no debería ser demasiado difícil.

Divulgación: Soy el autor original de pypreprocessor.

Aparte: originalmente lo escribí como una solución para el temido problema de mantenimiento de Python 2k / 3x. Mi enfoque fue, hacer el desarrollo 2 y 3 en los mismos archivos de origen y solo incluir / excluir las diferencias usando directivas de preprocesador. Desafortunadamente, descubrí que es imposible escribir un verdadero procesador puro (es decir, no requiere c) en Python porque el lexer marca los errores de sintaxis en un código incompatible antes de que el preprocesador tenga la oportunidad de ejecutarse. De cualquier manera, sigue siendo útil en una amplia gama de circunstancias, incluida la suya.

    
respondido por el Evan Plaice 08.11.2012 - 03:37
1

Probablemente sería una buena idea

1.addar etiquetas de comentarios como:

> // *COPYRIGHT-BEGIN-TAG*
> // Copyright 2012 (C) Acme Technology, All Rights Reserved.
> // Very large, often varied and restrictive copyright license in English and French,
> // sometimes also embedded in make files and shell scripts with varied 
> // comment styles. 
> // *COPYRIGHT-ENG-TAG*
>   ... Usual header stuff...
>
> void initTechnologyLibrary() {
>     nuiInterface(on);
> #ifdef  UNDER_RESEARCH
>     holographicVisualization(on);
> #endif
> }

2. Escribir script para que el generador de código abierto pase por todos los archivos y reemplace el texto entre las etiquetas COPYRIGHT-BEGIN-TAG y COPYRIGHT-ENG-TAG

    
respondido por el Alex Hashimi 08.11.2012 - 02:13
1

No voy a mostrarte una herramienta para convertir tu base de código, muchas respuestas ya lo hicieron. Más bien, estoy respondiendo a tu comentario sobre cómo manejar las sucursales para esto.

Deberías tener 2 ramas:

  • Comunidad (llamemos a la versión de código abierto como esta)
  • Profesional (llamemos a la versión de código cerrado como esta)

Los preprocesadores no deberían existir. Tienes dos versiones diferentes. Y un código base más limpio en general.

¿Tienes miedo de mantener dos copias en paralelo? No te preocupes, puedes fusionar!

Si está realizando modificaciones en la rama de la comunidad, simplemente fusionelas en la rama profesional. Git maneja este realmente bien.

De esta manera, mantienes 2 copias mantenidas de tu base de código. Y lanzar uno para fuente abierta es tan fácil como circular.

    
respondido por el Florian Margaine 08.11.2012 - 09:04

Lea otras preguntas en las etiquetas