<commit_before>package main

import (
	"context"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/ash2k/smith/pkg/app"
	"github.com/ash2k/smith/pkg/client"
	"github.com/ash2k/smith/pkg/processor"
)

func main() {
	ctx, cancelFunc := context.WithCancel(context.Background())
	defer cancelFunc()
	cancelOnInterrupt(ctx, cancelFunc)

	if err := runApp(ctx); err != nil && err != context.Canceled && err != context.DeadlineExceeded {
		log.Fatalln(err)
	}
}

func runApp(ctx context.Context) error {
	c, err := client.NewInCluster()
	if err != nil {
		return err
	}
	c.Agent = "smith/" + Version + "/" + GitCommit

	allEvents := make(chan interface{})
	subCtx, subCancel := context.WithCancel(ctx)
	defer subCancel()

	watcher := app.NewWatcher(subCtx, c, allEvents)
	defer watcher.Join() // await termination
	defer subCancel()    // cancel ctx to signal done to watcher. If anything below panics, this will be called

	tp := processor.New(subCtx, c)
	defer tp.Join()   // await termination
	defer subCancel() // cancel ctx to signal done to processor (and everything else)

	a := app.App{
		Watcher:   watcher,
		Client:    c,
		Processor: tp,
		Events:    allEvents,
	}
	return a.Run(ctx)
}

// cancelOnInterrupt calls f when os.Interrupt or SIGTERM is received.
// It ignores subsequent interrupts on purpose - program should exit correctly after the first signal.
func cancelOnInterrupt(ctx context.Context, f context.CancelFunc) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		select {
		case <-ctx.Done():
		case <-c:
			f()
		}
	}()
}
<commit_msg>Make sure defer is executed before log.Fatal<commit_after>package main

import (
	"context"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/ash2k/smith/pkg/app"
	"github.com/ash2k/smith/pkg/client"
	"github.com/ash2k/smith/pkg/processor"
)

func main() {
	if err := run(); err != nil && err != context.Canceled && err != context.DeadlineExceeded {
		log.Fatalln(err)
	}
}

func run() error {
	ctx, cancelFunc := context.WithCancel(context.Background())
	defer cancelFunc()
	cancelOnInterrupt(ctx, cancelFunc)

	return runWithContext(ctx)
}

func runWithContext(ctx context.Context) error {
	c, err := client.NewInCluster()
	if err != nil {
		return err
	}
	c.Agent = "smith/" + Version + "/" + GitCommit
	return runWithClient(ctx, c)
}

func runWithClient(ctx context.Context, c *client.ResourceClient) error {
	allEvents := make(chan interface{})
	subCtx, subCancel := context.WithCancel(ctx)
	defer subCancel()

	watcher := app.NewWatcher(subCtx, c, allEvents)
	defer watcher.Join() // await termination
	defer subCancel()    // cancel ctx to signal done to watcher. If anything below panics, this will be called

	tp := processor.New(subCtx, c)
	defer tp.Join()   // await termination
	defer subCancel() // cancel ctx to signal done to processor (and everything else)

	a := app.App{
		Watcher:   watcher,
		Client:    c,
		Processor: tp,
		Events:    allEvents,
	}
	return a.Run(ctx)
}

// cancelOnInterrupt calls f when os.Interrupt or SIGTERM is received.
// It ignores subsequent interrupts on purpose - program should exit correctly after the first signal.
func cancelOnInterrupt(ctx context.Context, f context.CancelFunc) {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
	go func() {
		select {
		case <-ctx.Done():
		case <-c:
			f()
		}
	}()
}

{'fraction_non_alphanumeric': 0.1321144205249189, 'fraction_numerical': 0.0023591860808021233, 'mean_word_length': 3.8388017118402282, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3662038', 'n_tokens_mistral': 1212, 'n_tokens_neox': 1166, 'n_words': 326}