2

I have a base sourcefile base.hs which I use create different extended versions of the same program (foo.hs, bar.hs, baz.hs). Now I want to create a patch file of every modified version but the patches should accumulate to get a program which includes all extensions.

base.hs

-- @@BEGIN_IMPORTS@@
-- @@END_IMPORTS@@

main = do
    -- @@BEGIN_EXTENSIONS@@
    -- @@END_EXTENSIONS@@
    putStrLn "Hello World"

foo.hs (note it's basically the same file)

-- @@BEGIN_IMPORTS@@
import Foo
-- @@END_IMPORTS@@

main = do
    -- @@BEGIN_EXTENSIONS@@
    putStrLn foo
    -- @@END_EXTENSIONS@@
    putStrLn "Hello World"

bar.hs

-- @@BEGIN_IMPORTS@@
import Bar
-- @@END_IMPORTS@@

main = do
    -- @@BEGIN_EXTENSIONS@@
    putStrLn bar
    -- @@END_EXTENSIONS@@
    putStrLn "Hello World"

baz.hs

-- @@BEGIN_IMPORTS@@
import Baz
-- @@END_IMPORTS@@

main = do
    -- @@BEGIN_EXTENSIONS@@
    putStrLn baz
    -- @@END_EXTENSIONS@@
    putStrLn "Hello World"

=>

extended.hs

-- @@BEGIN_IMPORTS@@
import Foo
import Bar
import Baz
-- @@END_IMPORTS@@

main = do
    -- @@BEGIN_EXTENSIONS@@
    putStrLn foo
    putStrLn bar
    putStrLn baz
    -- @@END_EXTENSIONS@@
    putStrLn "Hello World"

diff + patch?

I'm aware of the diff and patch utilities but the problem is if I apply multiple patches they cancel each other out (hence I'd get baz.hs).

NOT WORKING

diff -c base.hs foo.hs > foo.hs.c3
diff -c base.hs bar.hs > bar.hs.c3
diff -c base.hs baz.hs > baz.hs.c3
patch -o base_foo.hs base.hs foo.hs.c3
patch -o base_foo_bar.hs base_foo.hs bar.hs.c3
patch -o base_foo_bar_baz.hs base_foo_bar.hs baz.hs.c3

combinediff?

I'm also aware of combinediff but this only works if the patches have been applied in sequential order, hence I'd need to produce the diff from base_foo.hs.

diff3?

Diff + patch - Sum instead of replace refers to the diff3 utility (patchutils package) but I don't seem to get the required behaviour working and besides I don't know how this would help with multiple patches.

NOT WORKING

touch null
diff3 foo.hs.c3 null bar.hs.c3 > foo_bar.hs.c3
patch -o base_foo_bar.hs base.hs foo_bar.hs.c3

(the idea here is to combine the diffs from an empty file)

NOT WORKING

diff3 -m foo.hs.c3 base.hs bar.hs.c3 > base_foo_bar.hs

(apparently it produces a big conflict file included all three versions)

misc?

I also had the idea of using the merge tools of SCMs like git but apparently they can only be used on commits but my files are not in version control.

My current solution is inserting the code snippets via perl -pi -e but it's rather laborous and errorprone.

Community
  • 1
  • 1
Gerold Meisinger
  • 4,500
  • 5
  • 26
  • 33
  • you don't tell if the solution should be automated, or if can be manual. BTW most SCMs merge Tools can be executed on arbitrary files, and some standalone merge tools might be able (even from command line). To automate that the problem lies in the fact that you want to accept conflicting text with a "A then B" approach, but is it always applicable inside the different portions of text themselves? – armel Sep 18 '13 at 14:11
  • I'd like to provide some patch files which are applied automatically, yes. I just found "git merge-file --union" which is a part solution, but it only merges whole files. This is a problem because I also have varying text in the files which I want to ignore. @A then B: I don't know if I understand you right but, yes it is always applicable. The text portions don't depend on each other. – Gerold Meisinger Sep 18 '13 at 14:24
  • 2
    if you need to ignore certain lines, you might be able to first diff (with some -I regexp), then apply individually the produced patches on the base file to produce one 'simplified' file per derived (this patched result is thus less different from the base file), you can merge those files. All the ignored portions won't conflict and stay as in the base file. – armel Sep 18 '13 at 21:26
  • good idea, that might work! – Gerold Meisinger Sep 19 '13 at 08:22

1 Answers1

0
# diffs can be created beforehand

diff base.hs foo.hs > foo.hs.diff
diff base.hs bar.hs > bar.hs.diff
diff base.hs baz.hs > baz.hs.diff

# *creating a mybase.hs here which is slightly different (like "Hello Mars")*

# the follow steps need to be done for every run

patch -o myfoo.hs mybase.hs foo.hs.diff
patch -o mybar.hs mybase.hs bar.hs.diff 
patch -o mybaz.hs mybase.hs baz.hs.diff

# we create a temp file here because it seems that merge-file and the stream operator '>'
# operate on the same file immediately
cp mybase.hs mybase_union.hs
git merge-file -p --union myfoo.hs mybase.hs mybase_union.hs         > mybase_union_foo.hs
git merge-file -p --union mybar.hs mybase.hs mybase_union_foo.hs     > mybase_union_foo_bar.hs
git merge-file -p --union mybaz.hs mybase.hs mybase_union_foo_bar.hs > mybase_union_foo_bar_baz.hs
cp mybase_union_foo_bar_baz.hs mybase_extended.hs

Thx armel!

Gerold Meisinger
  • 4,500
  • 5
  • 26
  • 33