<commit_before>// +build darwin

package darwin

// InterfaceGenerator XXX
type InterfaceGenerator struct {
}

// Key XXX
func (g *InterfaceGenerator) Key() string {
	return "interface"
}

// Generate XXX
func (g *InterfaceGenerator) Generate() (interface{}, error) {
	var interfaces map[string]map[string]interface{}

	// TODO

	return interfaces, nil
}
<commit_msg>implementation of codes retrieving interface on Darwin<commit_after>// +build darwin

package darwin

import (
	"bufio"
	"bytes"
	"os/exec"
	"regexp"

	"github.com/mackerelio/mackerel-agent/logging"
)

// InterfaceGenerator XXX
type InterfaceGenerator struct {
}

// Key XXX
func (g *InterfaceGenerator) Key() string {
	return "interface"
}

var interfaceLogger = logging.GetLogger("spec.interface")

// Generate XXX
func (g *InterfaceGenerator) Generate() (interface{}, error) {
	var interfaces map[string]map[string]interface{}

	interfaces, err := g.generateByIfconfigCommand()
	if err != nil {
		return nil, err
	}

	var results []map[string]interface{}
	for key, iface := range interfaces {
		if iface["loopback"] != nil {
			continue
		}
		if iface["ipAddress"] == nil && iface["ipv6Address"] == nil {
			continue
		}
		iface["name"] = key
		results = append(results, iface)
	}

	return results, nil
}

func (g *InterfaceGenerator) generateByIfconfigCommand() (map[string]map[string]interface{}, error) {
	interfaces := make(map[string]map[string]interface{})

	{
		// ifconfig -a
		out, err := exec.Command("ifconfig", "-a").Output()
		if err != nil {
			interfaceLogger.Errorf("Failed to run ifconfig command (skip this spec): %s", err)
			return nil, err
		}

		lineScanner := bufio.NewScanner(bytes.NewReader(out))
		name := ""
		for lineScanner.Scan() {
			line := lineScanner.Text()
			// ex.) en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
			if matches := regexp.MustCompile(`^([0-9a-zA-Z@\-_]+):\s+`).FindStringSubmatch(line); matches != nil {
				name = matches[1]
				interfaces[name] = make(map[string]interface{}, 0)
			}
			// ex.) lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
			if regexp.MustCompile(`LOOPBACK`).MatchString(line) {
				interfaces[name]["loopback"] = true
			}
			// ex.) ether 10:93:00:00:00:00
			if matches := regexp.MustCompile(`^\s*ether\s+([0-9a-f:]+)`).FindStringSubmatch(line); matches != nil {
				interfaces[name]["macAddress"] = matches[1]
			}
			// ex.) inet 10.0.3.1 netmask 0xffffff00 broadcast 10.0.3.255
			if matches := regexp.MustCompile(`^\s*inet\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+netmask\s+(0x[0-9a-f]+)`).FindStringSubmatch(line); matches != nil {
				interfaces[name]["ipAddress"] = matches[1]
				interfaces[name]["netmask"] = matches[2]
			}
			// ex.) inet6 fd00:c2b6:b24b:be67:2827:688d:e6a1:6a3b prefixlen 64 autoconf
			if matches := regexp.MustCompile(`^\s*inet6\s+([0-9a-f:]+)\s+prefixlen\s+(\d+)`).FindStringSubmatch(line); matches != nil {
				interfaces[name]["ipv6Address"] = matches[1]
				interfaces[name]["v6netmask"] = matches[2]
			}
		}
	}

	{
		// netstat -f inet -rn
		out, err := exec.Command("netstat", "-f", "inet", "-rn").Output()
		if err != nil {
			interfaceLogger.Errorf("Failed to run netstat command (skip this spec): %s", err)
			return interfaces, err
		}
		routeRegexp := regexp.MustCompile(`^default\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`)
		lineScanner := bufio.NewScanner(bytes.NewReader(out))
		// ex.)
		// Routing tables

		// Internet:
		// Destination        Gateway            Flags        Refs      Use   Netif Expire
		// default            10.0.3.1      UGSc           25        0     en0
		for lineScanner.Scan() {
			line := lineScanner.Text()
			if routeRegexp.FindStringSubmatch(line) != nil {
				routeResults := regexp.MustCompile(`[ \t]+`).Split(line, 6)
				if len(routeResults) < 6 || interfaces[routeResults[5]] == nil {
					continue
				}
				interfaces[routeResults[5]]["defaultGateway"] = routeResults[1]
				break
			}
		}
	}

	{
		// arp -an
		out, err := exec.Command("arp", "-an").Output()
		if err != nil {
			interfaceLogger.Errorf("Failed to run arp command (skip this spec): %s", err)
			return interfaces, err
		}

		arpRegexp := regexp.MustCompile(`^\S+ \((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\) at ([a-fA-F0-9\:]+) on ([0-9a-zA-Z@\-_]+) ifscope \[(\w+)\]`)
		lineScanner := bufio.NewScanner(bytes.NewReader(out))
		for lineScanner.Scan() {
			line := lineScanner.Text()
			// ex.) ? (10.0.3.1) at 01:23:45:67:89:ab on en0 ifscope [ethernet]
			if matches := arpRegexp.FindStringSubmatch(line); matches != nil {
				if interfaces[matches[3]] == nil {
					continue
				}
				interfaces[matches[3]]["address"] = matches[1]
				break
			}
		}
	}

	return interfaces, nil
}

{'fraction_non_alphanumeric': 0.18064105285502016, 'fraction_numerical': 0.031628104436425386, 'mean_word_length': 3.574757281553398, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, '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': '6310837', 'n_tokens_mistral': 1962, 'n_tokens_neox': 1714, 'n_words': 343}