package patch

  1. Overview
  2. Docs
Patch library purely in OCaml

Install

Dune Dependency

Authors

Maintainers

Sources

patch-1.0.1.tbz
sha256=574c66646223c37eeccc2d91763821da812c1a57681b43c99d21c9145a69613b
sha512=1e924fa1f112e2a6181ce2c4062dd21ed50310437d9befd280a6dcf019ec16295e7d4bbcf34b042bc768b6aa080043851c0675ac7de8c22b67add041f4569b13

Description

This is a library which parses unified diff and git diff output, and can apply a patch in memory.

Published: 28 Oct 2022

README

Patch - apply your unified diffs in pure OCaml

The loosely specified diff file format is widely used for transmitting differences of line-based information. The motivating example is opam, which is able to validate updates being cryptographically signed (e.g. conex) by providing a unified diff.

The test-based infered specification implemented in this library is the following grammar.

decimal := [0-9]+
any := any character except newline

filename := "/dev/null" | any except tab character
file := filename "\t" any "\n"
mine := "--- " file
theirs := "+++ " file

no_newline = "\ No newline at end of file"
hunk_line_prefix := " " | "-" | "+"
hunk_line := hunk_line_prefix any | no_newline
range := decimal "," decimal | decimal
hunk_hdr := "@@ -" range " + " range " @@\n"
hunk := hunk_hdr line+

diff := mine theirs hunk+

In addition, some support for the git diff format is available, which contains diff --git a/nn b/nn as separator, prefixes filenames with a/ and b/, and may contain extra headers, especially for pure renaming: rename from <path> followed by rename to <path>. The git diff documentation also mentions that a diff file itself should be an atomic operation, thus all - files corrspond to the files before applying the diff (since patch only does single diff operations, and requires the old content as input). You have to ensure to provide the correct data yourself.

A diff consists of a two-line header containing the filenames (or "/dev/null" for creation and deletion) followed by the actual changes in hunks. A complete diff file is represented by a list of diff elements. The OCaml types below, provided by this library, represent mine and theirs as operation (edit, rename, delete, create). Since a diff is line-based, if the file does not end with a newline character, the line in the diff always contains a newline, but the special marker no_newline is added to the diff. The range information carries start line and chunk size in the respective file, with two side conditions: if the chunk size is 0, the start line refers to after which the chunk should be added or deleted, and if the chunk size is omitted (including the comma), it is set to 1. NB from practical experiments, only "+1" and "-1" are supported.

type operation =
  | Edit of string
  | Rename of string * string
  | Delete of string
  | Create of string
  | Rename_only of string * string

type hunk (* positions and contents *)

type t = {
  operation : operation ;
  hunks : hunk list ;
  mine_no_nl : bool ;
  their_no_nl : bool ;
}

Shortcomings

The function patch assumes that the patch applies cleanly, and does not check this assumption. Exceptions may be raised if this assumption is violated. The git diff format allows further features, such as file permissions, and also a "copy from / to" header, which I was unable to spot in the wild.

Installation

opam install patch

Documentation

The API documentation can be browsed online.

Dependencies (2)

  1. dune
  2. ocaml >= "4.04.2"

Dev Dependencies (2)

  1. crowbar with-test
  2. alcotest with-test

Used by

None

Conflicts

None