<commit_before>package modules

import (
	"fmt"
	"os"
	"os/user"
	"strconv"

	"github.com/wx13/genesis"
)

type File struct {
	Path   string
	Mode   os.FileMode
	Owner  string
	Absent bool
	Local  bool // Don't follow links
}

func (file File) Describe() string {
	return fmt.Sprintf("File: %+v", file)
}

func (file File) ID() string {
	return fmt.Sprintf("file %+v", file)
}

func (file File) Status() (genesis.Status, string, error) {
	stat, err := os.Stat(file.Path)
	if file.Local {
		stat, err = os.Lstat(file.Path)
	}
	if file.Absent {
		if err == nil {
			return genesis.StatusFail, "File exists", nil
		}
		return genesis.StatusPass, "File does not exist", nil
	}
	if err != nil {
		return genesis.StatusFail, "Cannot stat file.", err
	}
	if stat.Mode() != file.Mode {
		msg := fmt.Sprintf("File mode should be %o, but is %o", file.Mode, stat.Mode())
		return genesis.StatusFail, msg, fmt.Errorf("Incorrect file permissions")
	}
	return genesis.StatusPass, "File mode is correct.", nil
}

func (file File) Remove() (string, error) {
	return "Cannot undo a file operation (not supported yet).", nil
}

func (file File) Install() (string, error) {
	if file.Absent {
		err := os.Remove(file.Path)
		if err != nil {
			return "Failed to remove file", err
		}
		return "Successfully removed file", nil
	}
	if len(file.Owner) > 0 {
		user, err := user.Lookup(file.Owner)
		if err != nil {
			return "Cannot lookup owner.", err
		}
		uid, _ := strconv.Atoi(user.Uid)
		gid, _ := strconv.Atoi(user.Gid)
		err = os.Chown(file.Path, uid, gid)
		if err != nil {
			return "Cannot change ownership.", err
		}
	}
	err := os.Chmod(file.Path, file.Mode)
	if err != nil {
		return "Cannot change permissions.", err
	}
	return "Successfully changed permissions.", nil
}
<commit_msg>Can now specify path glob for file module<commit_after>package modules

import (
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strconv"

	"github.com/wx13/genesis"
)

type File struct {
	Path   string
	Mode   os.FileMode
	Owner  string
	Absent bool
	Local  bool // Don't follow links
}

func (file File) Describe() string {
	return fmt.Sprintf("File: %+v", file)
}

func (file File) ID() string {
	return fmt.Sprintf("file %+v", file)
}

type fileStat struct {
	path string
	info os.FileInfo
	err  error
}

func (file File) globStat() []fileStat {
	stats := []fileStat{}
	paths, err := filepath.Glob(file.Path)
	if err != nil {
		return stats
	}
	for _, p := range paths {
		stat, err := os.Stat(p)
		if file.Local {
			stat, err = os.Lstat(p)
		}
		stats = append(stats, fileStat{
			path: p,
			info: stat,
			err:  err,
		})
	}
	return stats
}

func (file File) Status() (genesis.Status, string, error) {
	stats := file.globStat()
	if file.Absent {
		for _, s := range stats {
			if s.err == nil {
				return genesis.StatusFail, "File exists: " + s.path, nil
			}
		}
		return genesis.StatusPass, "File does not exist", nil
	}
	for _, s := range stats {
		if s.err != nil {
			return genesis.StatusFail, "Cannot stat file: " + s.path, s.err
		}
		if s.info.Mode() != file.Mode {
			msg := fmt.Sprintf("File mode should be %o, but is %o", file.Mode, s.info.Mode())
			return genesis.StatusFail, msg, fmt.Errorf("Incorrect file permissions")
		}
	}
	return genesis.StatusPass, "File mode is correct.", nil
}

func (file File) Remove() (string, error) {
	return "Cannot undo a file operation (not supported yet).", nil
}

func (file File) Install() (string, error) {
	if file.Absent {
		err := os.Remove(file.Path)
		if err != nil {
			return "Failed to remove file", err
		}
		return "Successfully removed file", nil
	}
	if len(file.Owner) > 0 {
		user, err := user.Lookup(file.Owner)
		if err != nil {
			return "Cannot lookup owner.", err
		}
		uid, _ := strconv.Atoi(user.Uid)
		gid, _ := strconv.Atoi(user.Gid)
		err = os.Chown(file.Path, uid, gid)
		if err != nil {
			return "Cannot change ownership.", err
		}
	}
	err := os.Chmod(file.Path, file.Mode)
	if err != nil {
		return "Cannot change permissions.", err
	}
	return "Successfully changed permissions.", nil
}

{'fraction_non_alphanumeric': 0.14561186650185415, 'fraction_numerical': 0.0014833127317676143, 'mean_word_length': 3.2860169491525424, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '1405130', 'n_tokens_mistral': 1558, 'n_tokens_neox': 1462, 'n_words': 461}