blob: 2c92f03f3bc740f36ec7c5a416b22056dab84cc0 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package fidlgen
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
)
type LazyWriter struct {
destination string
temp *os.File
}
func NewLazyWriter(destination string) (*LazyWriter, error) {
dest_dir := filepath.Dir(destination)
err := os.MkdirAll(dest_dir, 0755)
if err != nil {
return nil, err
}
temp, err := ioutil.TempFile(dest_dir, filepath.Base(destination)+".*")
if err != nil {
return nil, err
}
return &LazyWriter{destination: destination, temp: temp}, nil
}
func (lw *LazyWriter) Write(p []byte) (n int, err error) {
return lw.temp.Write(p)
}
func (lw *LazyWriter) Close() error {
temp_name := lw.temp.Name()
// always clean up the temporary file
defer os.Remove(temp_name)
err := lw.temp.Close()
if err != nil {
return err
}
temp_stat, err := os.Stat(temp_name)
if err != nil {
return err
}
dest_stat, err := os.Stat(lw.destination)
if os.IsNotExist(err) {
// destination doesn't exist yet
return os.Rename(temp_name, lw.destination)
}
if err != nil {
return err
}
if temp_stat.Size() != dest_stat.Size() {
// sizes don't match, replace it
return os.Rename(temp_name, lw.destination)
}
temp, err := os.ReadFile(temp_name)
if err != nil {
return err
}
dest, err := os.ReadFile(lw.destination)
if err != nil {
return err
}
if !bytes.Equal(temp, dest) {
// contents don't match, replace
return os.Rename(temp_name, lw.destination)
}
return nil
}