func DiffFilesP(paths []string) Patch { args := stringslice.Cat([]string{"-p", "--"}, paths) o,e := git.ReadS("diff-files", args) error.FailOn(e) p, e := patch.Parse([]byte(o)); error.FailOn(e) return Patch(*p) }
func main() { flag.Usage = usage flag.Parse() args := flag.Args() var data []byte var err os.Error switch len(args) { case 0: data, err = ioutil.ReadAll(os.Stdin) case 1: data, err = ioutil.ReadFile(args[0]) default: usage() } chk(err) pset, err := patch.Parse(data) chk(err) // Change to hg root directory, because // patch paths are relative to root. root, err := hgRoot() chk(err) chk(os.Chdir(root)) // Make sure there are no pending changes on the server. if *checkSync && hgIncoming() { fmt.Fprintf(os.Stderr, "incoming changes waiting; run hg sync first\n") os.Exit(2) } // Make sure we won't be editing files with local pending changes. dirtylist, err := hgModified() chk(err) dirty := make(map[string]int) for _, f := range dirtylist { dirty[f] = 1 } conflict := make(map[string]int) for _, f := range pset.File { if f.Verb == patch.Delete || f.Verb == patch.Rename { if _, ok := dirty[f.Src]; ok { conflict[f.Src] = 1 } } if f.Verb != patch.Delete { if _, ok := dirty[f.Dst]; ok { conflict[f.Dst] = 1 } } } if len(conflict) > 0 { fmt.Fprintf(os.Stderr, "cannot apply patch to locally modified files:\n") for name := range conflict { fmt.Fprintf(os.Stderr, "\t%s\n", name) } os.Exit(2) } // Apply changes in memory. op, err := pset.Apply(ioutil.ReadFile) chk(err) // Write changes to disk copy: order of commands matters. // Accumulate undo log as we go, in case there is an error. // Also accumulate list of modified files to print at end. changed := make(map[string]int) // Copy, Rename create the destination file, so they // must happen before we write the data out. // A single patch may have a Copy and a Rename // with the same source, so we have to run all the // Copy in one pass, then all the Rename. for i := range op { o := &op[i] if o.Verb == patch.Copy { makeParent(o.Dst) chk(hgCopy(o.Dst, o.Src)) undoRevert(o.Dst) changed[o.Dst] = 1 } } for i := range op { o := &op[i] if o.Verb == patch.Rename { makeParent(o.Dst) chk(hgRename(o.Dst, o.Src)) undoRevert(o.Dst) undoRevert(o.Src) changed[o.Src] = 1 changed[o.Dst] = 1 } } // Run Delete before writing to files in case one of the // deleted paths is becoming a directory. for i := range op { o := &op[i] if o.Verb == patch.Delete { chk(hgRemove(o.Src)) undoRevert(o.Src) changed[o.Src] = 1 } } // Write files. for i := range op { o := &op[i] if o.Verb == patch.Delete { continue } if o.Verb == patch.Add { makeParent(o.Dst) changed[o.Dst] = 1 } if o.Data != nil { chk(ioutil.WriteFile(o.Dst, o.Data, 0644)) if o.Verb == patch.Add { undoRm(o.Dst) } else { undoRevert(o.Dst) } changed[o.Dst] = 1 } if o.Mode != 0 { chk(os.Chmod(o.Dst, o.Mode&0755)) undoRevert(o.Dst) changed[o.Dst] = 1 } } // hg add looks at the destination file, so it must happen // after we write the data out. for i := range op { o := &op[i] if o.Verb == patch.Add { chk(hgAdd(o.Dst)) undoRevert(o.Dst) changed[o.Dst] = 1 } } // Finished editing files. Write the list of changed files to stdout. list := make([]string, len(changed)) i := 0 for f := range changed { list[i] = f i++ } sort.SortStrings(list) for _, f := range list { fmt.Printf("%s\n", f) } }