会社の機密研究コードからのオープンソースコードリリースの作成を最適に管理するにはどうすればよいですか?


13

私の会社(Acme Technologyと呼びます)には、元々Acme Labsの研究グループから来た数千のソースファイルのライブラリがあり、開発グループで数年間インキュベートされ、最近では少数の顧客に提供されています非開示。Acmeは、おそらくコードの75%をオープンソースコミュニティにリリースする準備をしています。他の25%は後でリリースされますが、現在のところ、顧客が使用する準備ができていないか、競合他社の手に渡らないようにする必要がある将来のイノベーションに関連するコードが含まれています。

現在、コードは#ifdefsでフォーマットされており、同じコードベースを、大学の研究者やはるかに広範な商業顧客がオープンソースに移行する前に利用できるプリプロダクションプラットフォームと連携することができます。実験とプロトタイピング、および将来のプラットフォームとの前方互換性テストに利用できます。単一のコードベースを維持することは、2つのコピーを並行して維持するのが困難な私のグループの経済性(および健全性)にとって不可欠であると考えられています。

現在のベースのファイルは次のようになります。

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

著作権を置き換え、#ifdefだけでなく#if defined(UNDER_RESEARCH)などのバリエーションを取り除くことができるツール、解析ライブラリ、または一般的なスクリプトはありますか?

コードは現在Gitにあり、Gitを使用する場所でホストされる可能性があります。リポジトリを安全にリンクして、オープンソースバージョンでの改善を効率的に再統合する方法はありますか?他の落とし穴についてのアドバイスは大歓迎です。


13
このコードベースはブランチを叫んでいます。
フロリアンマーゲイン

この目的でブランチを使用する例は大歓迎です。
DeveloperDon

回答:


6

プリプロセッサを解析するスクリプトを作成するにはあまりにも難しいことではないだろうと同じように、定義された定数(のリストにそれらを比較すると思われるUNDER_RESEARCHFUTURE_DEVELOPMENTディレクティブは与えられた偽に評価できる場合は削除のすべてのアップ、定義されているもの、など)と、次へ#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(のような)それらを保存するために使用できますが、それでもあなたはまだ古い著作権表示を取り除く必要があります
  • #includesも展開されるため、最終的に含まれるヘッダーファイルのすべてのコンテンツを含む大きなファイルになります。
  • 「標準」マクロは失われます。

展開されるマクロを制限する方法があるかもしれません。ただし、ここでの私の提案は、ファイルに対して(潜在的に危険な)処理を行う代わりに、物事を分割することです(ちなみに、その後、どのようにファイルを維持する予定ですか。たとえば、オープンソースバージョンからクローズドソースにコードを再導入しますか?)

つまり、オープンソースにするコードを可能な限り外部ライブラリに配置し、他のライブラリと同じように使用して、他の「カスタム」クローズドソースライブラリと統合してみてください。

物事を再構築する方法を理解するのに最初は少し時間がかかるかもしれませんが、これを達成するための間違いなく正しい方法です。


プリプロセッサを使用して、まだリリースしていないブロックを選択的に削除することができるかどうかを検討していました。コードは複雑で、必要なコメントは少なくなるよりも多くなりますが、ブレインストーミングリストに記載する価値はあります。WRTは、ソースをどのように維持し、コードをコミュニティに前後に移動させるかについて質問しています。さらに計画が必要です。プロプライエタリコードにコードを組み込むと、いくつかの良い疑問が生じます。
DeveloperDon

2

私は解決策を持っていますが、少し手間がかかります

pypreprocessorは、他のタイプのソースコードのGPP(汎用プリプロセッサ)としても使用できるPython用の純粋なcスタイルのプリプロセッサを提供するライブラリです。

基本的な例を次に示します。

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は、バイトコードへのコンパイル中にコメント付きコードを自動的に削除するため、明示的に設定する必要はありません。

エッジケースは1つしかありません。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を必要としない)プリプロセッサを書くことが難しい難しい方法を発見しました。いずれにせよ、それはあなたを含む幅広い状況下でまだ有用です。


これは揺れます。除外したいコードの有無にかかわらずファイルを処理する3ウェイdiffのように他に何もできなかった場合、それらのdiffを取得し、元のdiff行を削除しました。
DeveloperDon

@DeveloperDonはい、それが一般的な考え方です。これを処理する方法はいくつかありますが、コミットとリリースのサイクルをどのように管理するかによって異なります。この作品は、それ以外の場合は退屈でエラーが発生しやすい作業の多くを自動化します。
エヴァンプライス

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-TAGタグCOPYRIGHT-ENG-TAGタグの間のテキストを置き換えるスクリプトを作成する


1
開始タグが必要ですか?これまでのところ、すべてのソースファイルは1行目の著作権で始まり、シェルスクリプトは2行目の著作権で始まります。ファイルがたくさんあるので、可能な限り最小限の手編集をしたいと思います。
DeveloperDon

一部のファイルでは、Doxygenを使用して、関数、パラメーター、および戻り値の名前を記述できます。まだそのようにセットアップされていないファイルについては、その方向にさらに進んだ選択をした場合、本当に多くの編集が必要になる可能性があります。
DeveloperDon

少なくとも一度は変更する必要があります。著作権ポリシーが変更された場合は、管理できます。
アレックス橋見

1

コードベースを変換するツールを紹介するつもりはありませんが、多くの回答が既にそれを行っています。むしろ、このためにブランチを処理する方法についてのあなたのコメントに答えています。

2つのブランチが必要です。

  • コミュニティ(このようにオープンソースバージョンを呼び出しましょう)
  • プロフェッショナル(このようなクローズドソースバージョンを呼び出しましょう)

プリプロセッサは存在しないはずです。2つの異なるバージョンがあります。そして、全体的なコードベースがよりクリーンになりました。

2つのコピーを並行して維持するのが怖いですか?心配する必要はありません、マージできます!

コミュニティブランチに変更を加える場合は、それらをプロフェッショナルブランチにマージするだけです。Gitはこれを本当にうまく処理します。

このようにして、コードベースの2つのメンテナンスされたコピーを保持します。そして、オープンソース向けにリリースするのは簡単です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.