如何最好地管理公司机密研究代码的开放源代码发布?


13

我公司(简称为Acme Technology)拥有大约一千个源文件库,这些文件最初来自其Acme Labs研究小组,在一个开发小组中孵化了几年,最近已提供给少数客户。非公开。Acme已准备好向开源社区发布大约75%的代码。其余25%将在以后发布,但是目前,要么尚未准备好供客户使用,要么包含与未来创新相关的代码,他们需要将这些创新保持在竞争对手的控制之下。

目前,该代码已使用#ifdefs格式化,该代码库允许相同的代码库与预生产平台一起使用,一旦开源,该研究平台将可供大学研究人员和更广泛的商业客户使用,同时可用于实验和原型设计以及与未来平台的向前兼容性测试。对于我们小组的经济(和理智)而言,保持单一代码库被认为是至关重要的,因为他们很难同时维护两个副本。

当前库中的文件如下所示:

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

我们希望将它们转换为:

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

是否有工具,解析库或流行的脚本可以替代版权并不仅去除#ifdefs,还可以去除诸如#ifdefined(UNDER_RESEARCH)之类的变体?

该代码当前位于Git中,并且很可能托管在使用Git的地方。是否有一种方法可以将存储库安全地链接在一起,以便我们可以将改进与开源版本有效地重新集成在一起?欢迎提供其他陷阱的建议。


13
该代码库为分支机构大喊大叫。
Florian Margaine

一个为此目的使用分支的示例将是非常受欢迎的。
DeveloperDon

Answers:


6

看起来这不会太难写一个脚本来分析预处理程序,把它们比作定义的常量(列表UNDER_RESEARCHFUTURE_DEVELOPMENT等等),如果该指令可以被评估为假Given公司的定义是什么,删除了一切到下一个#endif

在Python中,我会做类似的事情,

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 xyz@acme.com 
// 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')

我敢肯定有更优雅的方法可以做到这一点,但这既快捷又肮脏,似乎可以完成工作。


哇谢谢。有很多逻辑可以构成一个好的过滤器,我感谢您的示例。我希望找到一些可以重用的东西,并且我的开发机器运行速度快且内存很大,因此对于版权和定义运行单独的过滤器,或者多次运行定义过滤器,性能并不是很大的关注。实际上,我们有多个与关键字相关的定义,这些定义指定了多个未来项目以及几个过去的项目,这些项目将不会以开源形式发布,但仍将在内部使用并由早期采用的客户使用。
DeveloperDon

3

我正在考虑通过预处理器传递代码以仅扩展宏,从而仅输出#ifdefs中有趣的部分。

这样的事情应该起作用:

gcc -E yourfile.c

但:

  • 您将丢失所有评论。您可以-CC(保留)它们,但仍然需要删除旧的版权声明。
  • #include也会被扩展,因此您最终将得到一个大文件,其中包含所包含的头文件的所有内容
  • 您将丢失“标准”宏。

可能有一种方法可以限制扩展哪些宏。但是,我的建议是拆分内容,而不是对文件进行处理(潜在危险)(顺便说一句,您打算在以后如何维护它们?例如,将代码从开源版本重新引入您的封闭源代码中?)。

也就是说,尝试将要开源的代码尽可能地放入外部库中,然后像使用任何其他库一样使用它们,并与其他“自定义”封闭源库集成。

最初可能需要花费一些时间才能弄清楚如何重组事物,但这绝对是实现此目标的正确方法。


我曾考虑过是否可以使用预处理器来选择性地消除我们尚未发布的块。代码很复杂,我们可能需要更多而不是更少的注释,但是您的建议肯定值得在头脑风暴列表中提出。WRT提出了有关我们如何计划维护源代码以及将代码前后移动到社区的疑问,这需要更多的计划。将代码引入专有代码会引起一些很好的问题。
DeveloperDon

2

我有一个解决方案,但需要一些工作

pypreprocessor是一个库,为python提供了纯c风格的预处理器,也可以用作其他类型的源代码的GPP(通用预处理器)。

这是一个基本示例:

from pypreprocessor import pypreprocessor

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

预处理器非常简单。它通过源并根据定义的条件有条件地注释掉源。

可以通过源中的#define语句或在pypreprocessor.defines列表中进行设置来设置定义。

设置输入/输出参数使您可以显式定义要打开/关闭的文件,因此可以根据需要设置单个预处理器以批量处理大量文件。

将removeMeta参数设置为True,预处理器应自动提取所有预处理器语句,仅保留后处理的代码。

注意:通常不需要显式设置,因为python在编译为字节码期间会自动删除注释的代码。

我只看到一个边缘情况。因为您要预处理C源代码,所以您可能希望显式设置处理器定义(即通过pypreprocessor.defines),并告诉它忽略源代码中的#define语句。这样可以避免意外删除项目源代码中可能使用的任何常量。当前没有参数可以设置此功能,但是添加起来很简单。

这是一个简单的例子:

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

然后来源:

#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 xyz@acme.com 
// for technical support, and www.acme.com/emergingTech for updates and RSS feed.
#endif

注意:显然,您需要选择一种设置输入/输出文件的方法,但这应该不会太困难。

披露:我是pypreprocessor的原始作者。


另外:我最初将其写为解决可怕的python 2k / 3x维护问题的解决方案。我的方法是,在相同的源文件中进行2和3开发,仅使用预处理程序指令包含/排除差异。不幸的是,我发现了一种很难的方法,即不可能在python中编写一个真正的纯(即不需要c)预处理器,因为在预处理器有机会运行之前,lexer会在不兼容的代码中标记语法错误。无论哪种方式,它在包括您在内的各种情况下仍然有用。


真厉害 如果没有其他办法,我们可以像使用三种方式的差异处理(使用和不使用我们要排除的代码处理文件)那样,进行差异处理,然后从原始文件中删除差异行。
DeveloperDon

@DeveloperDon Yep,这是总体思路。有几种不同的处理方式,这取决于您计划如何管理提交发布周期。这件作品只是自动化了许多工作,这些工作原本是乏味和/或容易出错的。
Evan Plaice 2012年

1

可能是个好主意

1.添加评论标签,如:

> // *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.为开源构建器编写脚本以遍历所有文件,并在COPYRIGHT-BEGIN-TAGCOPYRIGHT-ENG-TAG标记之间替换文本


1
我需要开始标记吗?到目前为止,我们所有的源文件都以第一行的版权开始,而我们的shell脚本以第二行的版权开始。文件很多,所以我想做尽可能少的手工编辑。
DeveloperDon

我认为某些文件可能使用Doxygen来描述其功能,参数和返回值名称。对于那些尚未以这种方式设置的文件,如果我们做出的选择可以进一步扩大该方向,那么实际上可能需要进行大量编辑。
DeveloperDon

至少您必须更改一次。如果您的版权政策有所更改,则可以对其进行管理。
亚历克斯·哈希米

1

我不会向您展示转换代码库的工具,已经有很多答案。相反,我正在回答您关于如何处理分支的评论。

您应该有2个分支:

  • 社区(让我们这样称呼开源版本)
  • 专业版(这样称呼封闭源代码版本)

预处理器不应该存在。您有两个不同的版本。整体而言,代码库更干净。

您担心并行维护两个副本吗?不用担心,您可以合并!

如果您要对社区分支进行修改,只需将它们合并到专业分支中即可。Git处理很好。

这样,您将保留2个代码库的维护副本。为开源发布一个很容易。

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.