<commit_before>/*
Package wmi provides a WQL interface for WMI on Windows.

Warning

Due to a memory bug (https://github.com/mattn/go-ole/issues/13) only use the wmi
package in its own executable and never within a package. This executable must
disable the GC and should either exit after running a query or safely exit after
running N queries (since memory use will go up). See this github issue
(https://github.com/StackExchange/wmi/issues/1) for more details.
*/
package wmi

import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"os"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"

	ole "github.com/mjibson/go-ole"
	"github.com/mjibson/go-ole/oleutil"
)

var l = log.New(os.Stdout, "", log.LstdFlags)

var (
	ErrInvalidEntityType = errors.New("wmi: invalid entity type")
)

func init() {
	go func() {
		runtime.LockOSThread()
		ole.CoInitializeEx(0, 0)
		for f := range mainfunc {
			f()
		}
	}()
}

// queue of work to run in main thread.
var mainfunc = make(chan func())

// do runs f on the main thread.
func do(f func() error) (err error) {
	done := make(chan bool, 1)
	mainfunc <- func() {
		err = f()
		done <- true
	}
	<-done
	return
}

// QueryNamespace invokes Query with the given namespace on the local machine.
func QueryNamespace(query string, dst interface{}, namespace string) error {
	return Query(query, dst, nil, namespace)
}

var lock = sync.Mutex{}

// Query runs the WQL query and appends the values to dst.
//
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
// the query must have the same name in dst. Supported types are all signed and
// unsigned integers, time.Time, string, bool. Array types are not supported.
// See wmi_test.go for some examples.
//
// By default, the local machine and default namespace are used. These can be
// changed using connectServerArgs. See
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
func Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
	lock.Lock()
	defer lock.Unlock()
	return runQuery(query, dst, connectServerArgs...)
}

func runQuery(query string, dst interface{}, connectServerArgs ...interface{}) (queryErr error) {
	f := func() error {
		dv := reflect.ValueOf(dst)
		if dv.Kind() != reflect.Ptr || dv.IsNil() {
			return ErrInvalidEntityType
		}
		dv = dv.Elem()
		mat, elemType := checkMultiArg(dv)
		if mat == multiArgTypeInvalid {
			return ErrInvalidEntityType
		}

		unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
		if err != nil {
			return err
		}
		defer unknown.Release()

		wmi, err := unknown.QueryInterface(ole.IID_IDispatch)
		if err != nil {
			return err
		}
		defer wmi.Release()

		// service is a SWbemServices
		serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", connectServerArgs...)
		if err != nil {
			return err
		}
		service := serviceRaw.ToIDispatch()
		defer service.Release()

		// result is a SWBemObjectSet
		resultRaw, err := oleutil.CallMethod(service, "ExecQuery", query)
		if err != nil {
			return err
		}
		result := resultRaw.ToIDispatch()
		defer result.Release()

		count, err := oleInt64(result, "Count")
		if err != nil {
			return err
		}

		var errFieldMismatch error
		for i := int64(0); i < count; i++ {
			err := func() error {
				// item is a SWbemObject, but really a Win32_Process
				itemRaw, err := oleutil.CallMethod(result, "ItemIndex", i)
				if err != nil {
					return err
				}
				item := itemRaw.ToIDispatch()
				defer item.Release()

				ev := reflect.New(elemType)
				if err = loadEntity(ev.Interface(), item); err != nil {
					if _, ok := err.(*ErrFieldMismatch); ok {
						// We continue loading entities even in the face of field mismatch errors.
						// If we encounter any other error, that other error is returned. Otherwise,
						// an ErrFieldMismatch is returned.
						errFieldMismatch = err
					} else {
						return err
					}
				}
				if mat != multiArgTypeStructPtr {
					ev = ev.Elem()
				}
				dv.Set(reflect.Append(dv, ev))
				return nil
			}()
			if err != nil {
				return err
			}
		}
		return errFieldMismatch
	}
	r := do(f)
	if r != nil && queryErr == nil {
		queryErr = r
	}
	return
}
<commit_msg>Remove all this single thread hoopla<commit_after>/*
Package wmi provides a WQL interface for WMI on Windows.

Warning

Due to a memory bug (https://github.com/mattn/go-ole/issues/13) only use the wmi
package in its own executable and never within a package. This executable must
disable the GC and should either exit after running a query or safely exit after
running N queries (since memory use will go up). See this github issue
(https://github.com/StackExchange/wmi/issues/1) for more details.
*/
package wmi

import (
	"bytes"
	"errors"
	"fmt"
	"log"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	ole "github.com/mjibson/go-ole"
	"github.com/mjibson/go-ole/oleutil"
)

var l = log.New(os.Stdout, "", log.LstdFlags)

var (
	ErrInvalidEntityType = errors.New("wmi: invalid entity type")
)

// QueryNamespace invokes Query with the given namespace on the local machine.
func QueryNamespace(query string, dst interface{}, namespace string) error {
	return Query(query, dst, nil, namespace)
}

var lock = sync.Mutex{}

// Query runs the WQL query and appends the values to dst.
//
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in
// the query must have the same name in dst. Supported types are all signed and
// unsigned integers, time.Time, string, bool. Array types are not supported.
// See wmi_test.go for some examples.
//
// By default, the local machine and default namespace are used. These can be
// changed using connectServerArgs. See
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details.
func Query(query string, dst interface{}, connectServerArgs ...interface{}) error {
	lock.Lock()
	defer lock.Unlock()
	return runQuery(query, dst, connectServerArgs...)
}

func runQuery(query string, dst interface{}, connectServerArgs ...interface{}) (queryErr error) {
	f := func() error {
		dv := reflect.ValueOf(dst)
		if dv.Kind() != reflect.Ptr || dv.IsNil() {
			return ErrInvalidEntityType
		}
		dv = dv.Elem()
		mat, elemType := checkMultiArg(dv)
		if mat == multiArgTypeInvalid {
			return ErrInvalidEntityType
		}

		unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
		if err != nil {
			return err
		}
		defer unknown.Release()

		wmi, err := unknown.QueryInterface(ole.IID_IDispatch)
		if err != nil {
			return err
		}
		defer wmi.Release()

		// service is a SWbemServices
		serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", connectServerArgs...)
		if err != nil {
			return err
		}
		service := serviceRaw.ToIDispatch()
		defer service.Release()

		// result is a SWBemObjectSet
		resultRaw, err := oleutil.CallMethod(service, "ExecQuery", query)
		if err != nil {
			return err
		}
		result := resultRaw.ToIDispatch()
		defer result.Release()

		count, err := oleInt64(result, "Count")
		if err != nil {
			return err
		}

		var errFieldMismatch error
		for i := int64(0); i < count; i++ {
			err := func() error {
				// item is a SWbemObject, but really a Win32_Process
				itemRaw, err := oleutil.CallMethod(result, "ItemIndex", i)
				if err != nil {
					return err
				}
				item := itemRaw.ToIDispatch()
				defer item.Release()

				ev := reflect.New(elemType)
				if err = loadEntity(ev.Interface(), item); err != nil {
					if _, ok := err.(*ErrFieldMismatch); ok {
						// We continue loading entities even in the face of field mismatch errors.
						// If we encounter any other error, that other error is returned. Otherwise,
						// an ErrFieldMismatch is returned.
						errFieldMismatch = err
					} else {
						return err
					}
				}
				if mat != multiArgTypeStructPtr {
					ev = ev.Elem()
				}
				dv.Set(reflect.Append(dv, ev))
				return nil
			}()
			if err != nil {
				return err
			}
		}
		return errFieldMismatch
	}
	ole.CoInitializeEx(0, 0)
	defer ole.CoUninitialize()
	r := f()
	if r != nil && queryErr == nil {
		queryErr = r
	}
	return
}

{'fraction_non_alphanumeric': 0.12000496401092083, 'fraction_numerical': 0.004591710101762224, 'mean_word_length': 3.1864935064935067, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 3, 'https://': 4, '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': '1926176', 'n_tokens_mistral': 2965, 'n_tokens_neox': 2600, 'n_words': 881}