<commit_before>package lib

import (
	"encoding/xml"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	. "github.com/ForceCLI/force/error"
)

// Structs for XML building
type Package struct {
	Xmlns   string     `xml:"xmlns,attr"`
	Types   []MetaType `xml:"types"`
	Version string     `xml:"version"`
}

type MetaType struct {
	Members []string `xml:"members"`
	Name    string   `xml:"name"`
}

func createPackage() Package {
	return Package{
		Version: strings.TrimPrefix(apiVersion, "v"),
		Xmlns:   "http://soap.sforce.com/2006/04/metadata",
	}
}

type metapath struct {
	path       string
	name       string
	hasFolder  bool
	onlyFolder bool
	extension  string
}

var metapaths = []metapath{
	metapath{path: "actionLinkGroupTemplates", name: "ActionLinkGroupTemplate"},
	metapath{path: "analyticSnapshots", name: "AnalyticSnapshot"},
	metapath{path: "applications", name: "CustomApplication"},
	metapath{path: "appMenus", name: "AppMenu"},
	metapath{path: "approvalProcesses", name: "ApprovalProcess"},
	metapath{path: "assignmentRules", name: "AssignmentRules"},
	metapath{path: "audience", name: "Audience"},
	metapath{path: "authproviders", name: "AuthProvider"},
	metapath{path: "aura", name: "AuraDefinitionBundle", hasFolder: true, onlyFolder: true},
	metapath{path: "autoResponseRules", name: "AutoResponseRules"},
	metapath{path: "callCenters", name: "CallCenter"},
	metapath{path: "cachePartitions", name: "PlatformCachePartition"},
	metapath{path: "certs", name: "Certificate"},
	metapath{path: "channelLayouts", name: "ChannelLayout"},
	metapath{path: "classes", name: "ApexClass"},
	metapath{path: "communities", name: "Community"},
	metapath{path: "components", name: "ApexComponent"},
	metapath{path: "connectedApps", name: "ConnectedApp"},
	metapath{path: "contentassets", name: "ContentAsset"},
	metapath{path: "corsWhitelistOrigins", name: "CorsWhitelistOrigin"},
	metapath{path: "customApplicationComponents", name: "CustomApplicationComponent"},
	metapath{path: "customMetadata", name: "CustomMetadata"},
	metapath{path: "notificationTypes", name: "CustomNotificationType"},
	metapath{path: "customPermissions", name: "CustomPermission"},
	metapath{path: "dashboards", name: "Dashboard", hasFolder: true},
	metapath{path: "dataSources", name: "ExternalDataSource"},
	metapath{path: "datacategorygroups", name: "DataCategoryGroup"},
	metapath{path: "delegateGroups", name: "DelegateGroup"},
	metapath{path: "documents", name: "Document", hasFolder: true},
	metapath{path: "duplicateRules", name: "DuplicateRule"},
	metapath{path: "EmbeddedServiceConfig", name: "EmbeddedServiceConfig"},
	metapath{path: "email", name: "EmailTemplate", hasFolder: true},
	metapath{path: "escalationRules", name: "EscalationRules"},
	metapath{path: "feedFilters", name: "CustomFeedFilter"},
	metapath{path: "flexipages", name: "FlexiPage"},
	metapath{path: "flowDefinitions", name: "FlowDefinition"},
	metapath{path: "flows", name: "Flow"},
	metapath{path: "globalPicklists", name: "GlobalPicklist"},
	metapath{path: "globalValueSets", name: "GlobalValueSet"},
	metapath{path: "globalValueSetTranslations", name: "GlobalValueSetTranslation"},
	metapath{path: "groups", name: "Group"},
	metapath{path: "homePageComponents", name: "HomePageComponent"},
	metapath{path: "homePageLayouts", name: "HomePageLayout"},
	metapath{path: "installedPackages", name: "InstalledPackage"},
	metapath{path: "labels", name: "CustomLabels"},
	metapath{path: "layouts", name: "Layout"},
	metapath{path: "LeadConvertSettings", name: "LeadConvertSettings"},
	metapath{path: "letterhead", name: "Letterhead"},
	metapath{path: "lwc", name: "LightningComponentBundle", hasFolder: true, onlyFolder: true},
	metapath{path: "matchingRules", name: "MatchingRules"},
	metapath{path: "matchingRules", name: "MatchingRule"},
	metapath{path: "namedCredentials", name: "NamedCredential"},
	metapath{path: "networks", name: "Network"},
	metapath{path: "objects", name: "CustomObject"},
	metapath{path: "objectTranslations", name: "CustomObjectTranslation"},
	metapath{path: "pages", name: "ApexPage"},
	metapath{path: "pathAssistants", name: "PathAssistant"},
	metapath{path: "permissionsets", name: "PermissionSet"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "profiles", name: "Profile", extension: ".profile"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "profiles", name: "Profile"},
	metapath{path: "profileSessionSettings", name: "ProfileSessionSetting"},
	metapath{path: "queues", name: "Queue"},
	metapath{path: "quickActions", name: "QuickAction"},
	metapath{path: "remoteSiteSettings", name: "RemoteSiteSetting"},
	metapath{path: "reports", name: "Report", hasFolder: true},
	metapath{path: "reportTypes", name: "ReportType"},
	metapath{path: "roles", name: "Role"},
	metapath{path: "scontrols", name: "Scontrol"},
	metapath{path: "settings", name: "Settings"},
	metapath{path: "sharingRules", name: "SharingRules"},
	metapath{path: "siteDotComSites", name: "SiteDotCom"},
	metapath{path: "sites", name: "CustomSite"},
	metapath{path: "standardValueSets", name: "StandardValueSet"},
	metapath{path: "staticresources", name: "StaticResource"},
	metapath{path: "synonymDictionaries", name: "SynonymDictionary"},
	metapath{path: "tabs", name: "CustomTab"},
	metapath{path: "translations", name: "Translations"},
	metapath{path: "triggers", name: "ApexTrigger"},
	metapath{path: "weblinks", name: "CustomPageWebLink"},
	metapath{path: "workflows", name: "Workflow"},
	metapath{path: "cspTrustedSites", name: "CspTrustedSite"},
}

type PackageBuilder struct {
	IsPush   bool
	Metadata map[string]MetaType
	Files    ForceMetadataFiles
}

func NewPushBuilder() PackageBuilder {
	pb := PackageBuilder{IsPush: true}
	pb.Metadata = make(map[string]MetaType)
	pb.Files = make(ForceMetadataFiles)

	return pb
}

func NewFetchBuilder() PackageBuilder {
	pb := PackageBuilder{IsPush: false}
	pb.Metadata = make(map[string]MetaType)
	pb.Files = make(ForceMetadataFiles)

	return pb
}

// Build and return package.xml
func (pb PackageBuilder) PackageXml() []byte {
	p := createPackage()

	for _, metaType := range pb.Metadata {
		p.Types = append(p.Types, metaType)
	}

	byteXml, _ := xml.MarshalIndent(p, "", "    ")
	byteXml = append([]byte(xml.Header), byteXml...)
	//if err := ioutil.WriteFile("mypackage.xml", byteXml, 0644); err != nil {
	//ErrorAndExit(err.Error())
	//}
	return byteXml
}

// Returns the full ForceMetadataFiles container
func (pb *PackageBuilder) ForceMetadataFiles() ForceMetadataFiles {
	pb.Files["package.xml"] = pb.PackageXml()
	return pb.Files
}

// Returns the source file path for a given metadata file path.
func MetaPathToSourcePath(mpath string) (spath string) {
	spath = strings.TrimSuffix(mpath, "-meta.xml")
	if spath == mpath {
		return
	}

	_, err := os.Stat(spath)
	if err != nil {
		spath = mpath
	}
	return
}

// Add a file to the builder
func (pb *PackageBuilder) AddFile(fpath string) (fname string, err error) {
	fpath, err = filepath.Abs(fpath)
	if err != nil {
		return
	}
	_, err = os.Stat(fpath)
	if err != nil {
		return
	}

	isDestructiveChanges, err := regexp.MatchString("destructiveChanges(Pre|Post)?"+regexp.QuoteMeta(".")+"xml", fpath)
	if err != nil {
		return
	}

	fpath = MetaPathToSourcePath(fpath)
	metaName, fname := getMetaTypeFromPath(fpath)
	if !isDestructiveChanges && !strings.HasSuffix(fpath, "-meta.xml") {
		pb.AddMetaToPackage(metaName, fname)
	}

	// If it's a push, we want to actually add the files
	if pb.IsPush {
		if isDestructiveChanges {
			err = pb.addDestructiveChanges(fpath)
		} else {
			err = pb.addFileToWorkingDir(metaName, fpath)
		}
	}

	return
}

//AddDirectory Recursively add files contained in provided directory
func (pb *PackageBuilder) AddDirectory(fpath string) (namePaths map[string]string, badPaths []string, err error) {
	namePaths = make(map[string]string)

	files, err := ioutil.ReadDir(fpath)
	if err != nil {
		badPaths = append(badPaths, fpath)
		return
	}

	for _, f := range files {
		dirOrFilePath := fpath + "/" + f.Name()
		if f.IsDir() {
			dirNamePaths, dirBadPath, err := pb.AddDirectory(dirOrFilePath)
			if err != nil {
				badPaths = append(badPaths, dirBadPath...)
			} else {
				for dirContentName, dirContentPath := range dirNamePaths {
					namePaths[dirContentName] = dirContentPath
				}
			}
		}

		name, err := pb.AddFile(dirOrFilePath)

		if (err != nil) || (name == "") {
			badPaths = append(badPaths, dirOrFilePath)
		} else {
			namePaths[name] = dirOrFilePath
		}
	}
	return
}

// Adds the file to a temp directory for deploy
func (pb *PackageBuilder) addFileToWorkingDir(metaName string, fpath string) (err error) {
	// Get relative dir from source
	srcDir := filepath.Dir(filepath.Dir(fpath))
	for _, mp := range metapaths {
		if metaName == mp.name && mp.hasFolder {
			srcDir = filepath.Dir(srcDir)
		}
	}
	frel, _ := filepath.Rel(srcDir, fpath)

	// Try to find meta file
	hasMeta := true
	fmeta := fpath + "-meta.xml"
	fmetarel := ""
	if _, err = os.Stat(fmeta); err != nil {
		if os.IsNotExist(err) {
			hasMeta = false
		} else {
			// Has error
			return
		}
	} else {
		// Should be present since we worked back to srcDir
		fmetarel, _ = filepath.Rel(srcDir, fmeta)
	}

	fdata, err := ioutil.ReadFile(fpath)
	if err != nil {
		return
	}

	pb.Files[frel] = fdata
	if hasMeta {
		fdata, err = ioutil.ReadFile(fmeta)
		pb.Files[fmetarel] = fdata
		return
	}

	return
}

func (pb *PackageBuilder) addDestructiveChanges(fpath string) (err error) {
	fdata, err := ioutil.ReadFile(fpath)
	if err != nil {
		return
	}

	frel, _ := filepath.Rel(filepath.Dir(fpath), fpath)
	pb.Files[frel] = fdata

	return
}

func (pb *PackageBuilder) contains(members []string, name string) bool {
	for _, a := range members {
		if a == name {
			return true
		}
	}
	return false
}

// Adds a metadata name to the pending package
func (pb *PackageBuilder) AddMetaToPackage(metaName string, name string) {
	mt := pb.Metadata[metaName]
	if mt.Name == "" {
		mt.Name = metaName
	}

	if !pb.contains(mt.Members, name) {
		mt.Members = append(mt.Members, name)
		pb.Metadata[metaName] = mt
	}
}

// Gets metadata type name and target name from a file path
func getMetaTypeFromPath(fpath string) (metaName string, name string) {
	fpath, err := filepath.Abs(fpath)
	if err != nil {
		ErrorAndExit("Cound not find " + fpath)
	}
	if _, err := os.Stat(fpath); err != nil {
		ErrorAndExit("Cound not open " + fpath)
	}

	// Get the metadata type and name for the file
	metaName, fileName := getMetaForPath(fpath)
	name = strings.TrimSuffix(fileName, filepath.Ext(fileName))
	//name = strings.TrimSuffix(name, filepath.Ext(name))
	return
}

func findMetapathForFile(file string) (path metapath) {
	parentDir := filepath.Dir(file)
	parentName := filepath.Base(parentDir)
	grandparentName := filepath.Base(filepath.Dir(parentDir))
	fileExtension := filepath.Ext(file)

	for _, mp := range metapaths {
		if mp.hasFolder && grandparentName == mp.path {
			return mp
		}
		if mp.path == parentName {
			return mp
		}
	}

	// Hmm, maybe we can use the extension to determine the type
	for _, mp := range metapaths {
		if mp.extension == fileExtension {
			return mp
		}
	}
	return
}

// Gets meta type and name based on a path
func getMetaForPath(path string) (metaName string, objectName string) {
	parentDir := filepath.Dir(path)
	parentName := filepath.Base(parentDir)
	grandparentName := filepath.Base(filepath.Dir(parentDir))
	fileName := filepath.Base(path)

	for _, mp := range metapaths {
		if mp.hasFolder && grandparentName == mp.path {
			metaName = mp.name
			if mp.onlyFolder {
				objectName = parentName
			} else {
				objectName = parentName + "/" + fileName
			}
			return
		}
		if mp.path == parentName {
			metaName = mp.name
			objectName = fileName
			return
		}
	}

	// Unknown, so use path
	metaName = parentName
	objectName = fileName
	return
}
<commit_msg>Fix Directory Name for CustomNotificationType Metadata<commit_after>package lib

import (
	"encoding/xml"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	. "github.com/ForceCLI/force/error"
)

// Structs for XML building
type Package struct {
	Xmlns   string     `xml:"xmlns,attr"`
	Types   []MetaType `xml:"types"`
	Version string     `xml:"version"`
}

type MetaType struct {
	Members []string `xml:"members"`
	Name    string   `xml:"name"`
}

func createPackage() Package {
	return Package{
		Version: strings.TrimPrefix(apiVersion, "v"),
		Xmlns:   "http://soap.sforce.com/2006/04/metadata",
	}
}

type metapath struct {
	path       string
	name       string
	hasFolder  bool
	onlyFolder bool
	extension  string
}

var metapaths = []metapath{
	metapath{path: "actionLinkGroupTemplates", name: "ActionLinkGroupTemplate"},
	metapath{path: "analyticSnapshots", name: "AnalyticSnapshot"},
	metapath{path: "applications", name: "CustomApplication"},
	metapath{path: "appMenus", name: "AppMenu"},
	metapath{path: "approvalProcesses", name: "ApprovalProcess"},
	metapath{path: "assignmentRules", name: "AssignmentRules"},
	metapath{path: "audience", name: "Audience"},
	metapath{path: "authproviders", name: "AuthProvider"},
	metapath{path: "aura", name: "AuraDefinitionBundle", hasFolder: true, onlyFolder: true},
	metapath{path: "autoResponseRules", name: "AutoResponseRules"},
	metapath{path: "callCenters", name: "CallCenter"},
	metapath{path: "cachePartitions", name: "PlatformCachePartition"},
	metapath{path: "certs", name: "Certificate"},
	metapath{path: "channelLayouts", name: "ChannelLayout"},
	metapath{path: "classes", name: "ApexClass"},
	metapath{path: "communities", name: "Community"},
	metapath{path: "components", name: "ApexComponent"},
	metapath{path: "connectedApps", name: "ConnectedApp"},
	metapath{path: "contentassets", name: "ContentAsset"},
	metapath{path: "corsWhitelistOrigins", name: "CorsWhitelistOrigin"},
	metapath{path: "customApplicationComponents", name: "CustomApplicationComponent"},
	metapath{path: "customMetadata", name: "CustomMetadata"},
	metapath{path: "notificationtypes", name: "CustomNotificationType"},
	metapath{path: "customPermissions", name: "CustomPermission"},
	metapath{path: "dashboards", name: "Dashboard", hasFolder: true},
	metapath{path: "dataSources", name: "ExternalDataSource"},
	metapath{path: "datacategorygroups", name: "DataCategoryGroup"},
	metapath{path: "delegateGroups", name: "DelegateGroup"},
	metapath{path: "documents", name: "Document", hasFolder: true},
	metapath{path: "duplicateRules", name: "DuplicateRule"},
	metapath{path: "EmbeddedServiceConfig", name: "EmbeddedServiceConfig"},
	metapath{path: "email", name: "EmailTemplate", hasFolder: true},
	metapath{path: "escalationRules", name: "EscalationRules"},
	metapath{path: "feedFilters", name: "CustomFeedFilter"},
	metapath{path: "flexipages", name: "FlexiPage"},
	metapath{path: "flowDefinitions", name: "FlowDefinition"},
	metapath{path: "flows", name: "Flow"},
	metapath{path: "globalPicklists", name: "GlobalPicklist"},
	metapath{path: "globalValueSets", name: "GlobalValueSet"},
	metapath{path: "globalValueSetTranslations", name: "GlobalValueSetTranslation"},
	metapath{path: "groups", name: "Group"},
	metapath{path: "homePageComponents", name: "HomePageComponent"},
	metapath{path: "homePageLayouts", name: "HomePageLayout"},
	metapath{path: "installedPackages", name: "InstalledPackage"},
	metapath{path: "labels", name: "CustomLabels"},
	metapath{path: "layouts", name: "Layout"},
	metapath{path: "LeadConvertSettings", name: "LeadConvertSettings"},
	metapath{path: "letterhead", name: "Letterhead"},
	metapath{path: "lwc", name: "LightningComponentBundle", hasFolder: true, onlyFolder: true},
	metapath{path: "matchingRules", name: "MatchingRules"},
	metapath{path: "matchingRules", name: "MatchingRule"},
	metapath{path: "namedCredentials", name: "NamedCredential"},
	metapath{path: "networks", name: "Network"},
	metapath{path: "objects", name: "CustomObject"},
	metapath{path: "objectTranslations", name: "CustomObjectTranslation"},
	metapath{path: "pages", name: "ApexPage"},
	metapath{path: "pathAssistants", name: "PathAssistant"},
	metapath{path: "permissionsets", name: "PermissionSet"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "profiles", name: "Profile", extension: ".profile"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "postTemplates", name: "PostTemplate"},
	metapath{path: "profiles", name: "Profile"},
	metapath{path: "profileSessionSettings", name: "ProfileSessionSetting"},
	metapath{path: "queues", name: "Queue"},
	metapath{path: "quickActions", name: "QuickAction"},
	metapath{path: "remoteSiteSettings", name: "RemoteSiteSetting"},
	metapath{path: "reports", name: "Report", hasFolder: true},
	metapath{path: "reportTypes", name: "ReportType"},
	metapath{path: "roles", name: "Role"},
	metapath{path: "scontrols", name: "Scontrol"},
	metapath{path: "settings", name: "Settings"},
	metapath{path: "sharingRules", name: "SharingRules"},
	metapath{path: "siteDotComSites", name: "SiteDotCom"},
	metapath{path: "sites", name: "CustomSite"},
	metapath{path: "standardValueSets", name: "StandardValueSet"},
	metapath{path: "staticresources", name: "StaticResource"},
	metapath{path: "synonymDictionaries", name: "SynonymDictionary"},
	metapath{path: "tabs", name: "CustomTab"},
	metapath{path: "translations", name: "Translations"},
	metapath{path: "triggers", name: "ApexTrigger"},
	metapath{path: "weblinks", name: "CustomPageWebLink"},
	metapath{path: "workflows", name: "Workflow"},
	metapath{path: "cspTrustedSites", name: "CspTrustedSite"},
}

type PackageBuilder struct {
	IsPush   bool
	Metadata map[string]MetaType
	Files    ForceMetadataFiles
}

func NewPushBuilder() PackageBuilder {
	pb := PackageBuilder{IsPush: true}
	pb.Metadata = make(map[string]MetaType)
	pb.Files = make(ForceMetadataFiles)

	return pb
}

func NewFetchBuilder() PackageBuilder {
	pb := PackageBuilder{IsPush: false}
	pb.Metadata = make(map[string]MetaType)
	pb.Files = make(ForceMetadataFiles)

	return pb
}

// Build and return package.xml
func (pb PackageBuilder) PackageXml() []byte {
	p := createPackage()

	for _, metaType := range pb.Metadata {
		p.Types = append(p.Types, metaType)
	}

	byteXml, _ := xml.MarshalIndent(p, "", "    ")
	byteXml = append([]byte(xml.Header), byteXml...)
	//if err := ioutil.WriteFile("mypackage.xml", byteXml, 0644); err != nil {
	//ErrorAndExit(err.Error())
	//}
	return byteXml
}

// Returns the full ForceMetadataFiles container
func (pb *PackageBuilder) ForceMetadataFiles() ForceMetadataFiles {
	pb.Files["package.xml"] = pb.PackageXml()
	return pb.Files
}

// Returns the source file path for a given metadata file path.
func MetaPathToSourcePath(mpath string) (spath string) {
	spath = strings.TrimSuffix(mpath, "-meta.xml")
	if spath == mpath {
		return
	}

	_, err := os.Stat(spath)
	if err != nil {
		spath = mpath
	}
	return
}

// Add a file to the builder
func (pb *PackageBuilder) AddFile(fpath string) (fname string, err error) {
	fpath, err = filepath.Abs(fpath)
	if err != nil {
		return
	}
	_, err = os.Stat(fpath)
	if err != nil {
		return
	}

	isDestructiveChanges, err := regexp.MatchString("destructiveChanges(Pre|Post)?"+regexp.QuoteMeta(".")+"xml", fpath)
	if err != nil {
		return
	}

	fpath = MetaPathToSourcePath(fpath)
	metaName, fname := getMetaTypeFromPath(fpath)
	if !isDestructiveChanges && !strings.HasSuffix(fpath, "-meta.xml") {
		pb.AddMetaToPackage(metaName, fname)
	}

	// If it's a push, we want to actually add the files
	if pb.IsPush {
		if isDestructiveChanges {
			err = pb.addDestructiveChanges(fpath)
		} else {
			err = pb.addFileToWorkingDir(metaName, fpath)
		}
	}

	return
}

//AddDirectory Recursively add files contained in provided directory
func (pb *PackageBuilder) AddDirectory(fpath string) (namePaths map[string]string, badPaths []string, err error) {
	namePaths = make(map[string]string)

	files, err := ioutil.ReadDir(fpath)
	if err != nil {
		badPaths = append(badPaths, fpath)
		return
	}

	for _, f := range files {
		dirOrFilePath := fpath + "/" + f.Name()
		if f.IsDir() {
			dirNamePaths, dirBadPath, err := pb.AddDirectory(dirOrFilePath)
			if err != nil {
				badPaths = append(badPaths, dirBadPath...)
			} else {
				for dirContentName, dirContentPath := range dirNamePaths {
					namePaths[dirContentName] = dirContentPath
				}
			}
		}

		name, err := pb.AddFile(dirOrFilePath)

		if (err != nil) || (name == "") {
			badPaths = append(badPaths, dirOrFilePath)
		} else {
			namePaths[name] = dirOrFilePath
		}
	}
	return
}

// Adds the file to a temp directory for deploy
func (pb *PackageBuilder) addFileToWorkingDir(metaName string, fpath string) (err error) {
	// Get relative dir from source
	srcDir := filepath.Dir(filepath.Dir(fpath))
	for _, mp := range metapaths {
		if metaName == mp.name && mp.hasFolder {
			srcDir = filepath.Dir(srcDir)
		}
	}
	frel, _ := filepath.Rel(srcDir, fpath)

	// Try to find meta file
	hasMeta := true
	fmeta := fpath + "-meta.xml"
	fmetarel := ""
	if _, err = os.Stat(fmeta); err != nil {
		if os.IsNotExist(err) {
			hasMeta = false
		} else {
			// Has error
			return
		}
	} else {
		// Should be present since we worked back to srcDir
		fmetarel, _ = filepath.Rel(srcDir, fmeta)
	}

	fdata, err := ioutil.ReadFile(fpath)
	if err != nil {
		return
	}

	pb.Files[frel] = fdata
	if hasMeta {
		fdata, err = ioutil.ReadFile(fmeta)
		pb.Files[fmetarel] = fdata
		return
	}

	return
}

func (pb *PackageBuilder) addDestructiveChanges(fpath string) (err error) {
	fdata, err := ioutil.ReadFile(fpath)
	if err != nil {
		return
	}

	frel, _ := filepath.Rel(filepath.Dir(fpath), fpath)
	pb.Files[frel] = fdata

	return
}

func (pb *PackageBuilder) contains(members []string, name string) bool {
	for _, a := range members {
		if a == name {
			return true
		}
	}
	return false
}

// Adds a metadata name to the pending package
func (pb *PackageBuilder) AddMetaToPackage(metaName string, name string) {
	mt := pb.Metadata[metaName]
	if mt.Name == "" {
		mt.Name = metaName
	}

	if !pb.contains(mt.Members, name) {
		mt.Members = append(mt.Members, name)
		pb.Metadata[metaName] = mt
	}
}

// Gets metadata type name and target name from a file path
func getMetaTypeFromPath(fpath string) (metaName string, name string) {
	fpath, err := filepath.Abs(fpath)
	if err != nil {
		ErrorAndExit("Cound not find " + fpath)
	}
	if _, err := os.Stat(fpath); err != nil {
		ErrorAndExit("Cound not open " + fpath)
	}

	// Get the metadata type and name for the file
	metaName, fileName := getMetaForPath(fpath)
	name = strings.TrimSuffix(fileName, filepath.Ext(fileName))
	//name = strings.TrimSuffix(name, filepath.Ext(name))
	return
}

func findMetapathForFile(file string) (path metapath) {
	parentDir := filepath.Dir(file)
	parentName := filepath.Base(parentDir)
	grandparentName := filepath.Base(filepath.Dir(parentDir))
	fileExtension := filepath.Ext(file)

	for _, mp := range metapaths {
		if mp.hasFolder && grandparentName == mp.path {
			return mp
		}
		if mp.path == parentName {
			return mp
		}
	}

	// Hmm, maybe we can use the extension to determine the type
	for _, mp := range metapaths {
		if mp.extension == fileExtension {
			return mp
		}
	}
	return
}

// Gets meta type and name based on a path
func getMetaForPath(path string) (metaName string, objectName string) {
	parentDir := filepath.Dir(path)
	parentName := filepath.Base(parentDir)
	grandparentName := filepath.Base(filepath.Dir(parentDir))
	fileName := filepath.Base(path)

	for _, mp := range metapaths {
		if mp.hasFolder && grandparentName == mp.path {
			metaName = mp.name
			if mp.onlyFolder {
				objectName = parentName
			} else {
				objectName = parentName + "/" + fileName
			}
			return
		}
		if mp.path == parentName {
			metaName = mp.name
			objectName = fileName
			return
		}
	}

	// Unknown, so use path
	metaName = parentName
	objectName = fileName
	return
}
<|endoftext|>


<commit_before>package alistorage

import (
	"strconv"
	"github.com/cloudlibz/gocloud/aliauth"
)

// Createdisk create ECS-Disk accept map[string]interface{}
func (aliStorage *Alistorage) Createdisk(request interface{}) (resp interface{}, err error) {
	var options CreateDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "RegionId":
			regionID, _ := value.(string)
			options.RegionID = regionID
		case "ZoneId":
			zoneID, _ := value.(string)
			options.ZoneID = zoneID
		case "DiskName":
			diskName, _ := value.(string)
			options.DiskName = diskName
		case "Description":
			description, _ := value.(string)
			options.Description = description
		case "Encrypted":
			switch value.(type) {
			case bool:
				options.Encrypted = value.(bool)
			case string:
				options.Encrypted = value.(string) == "true" || value.(string) == "True"
			}
		case "DiskCategory":
			diskCategory, _ := value.(string)
			options.DiskCategory = diskCategory
		case "Size":
			switch value.(type) {
			case int:
				options.Size = value.(int)
			case string:
				options.Size, _ = strconv.Atoi(value.(string))
			}
		case "SnapshotId":
			snapshotID, _ := value.(string)
			options.SnapshotID = snapshotID
		case "ClientToken":
			clientToken, _ := value.(string)
			options.ClientToken = clientToken
		}
	}

	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("CreateDisk", params, response)
	resp = response
	return resp, err
}

// Deletedisk delete ECS-Disk accept map[string]interface{}
func (aliStorage *Alistorage) Deletedisk(request interface{}) (resp interface{}, err error) {
	var options DeleteDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("DeleteDisk", params, response)
	resp = response
	return resp, err
}

//TODO
func (aliStorage *Alistorage) Createsnapshot(request interface{}) (resp interface{}, err error) {
	return resp, err
}

//TODO
func (aliStorage *Alistorage) Deletesnapshot(request interface{}) (resp interface{}, err error) {
	return resp, err
}

// Attachdisk attach ECS-Disk to ECS, accept map[string]interface{}
func (aliStorage *Alistorage) Attachdisk(request interface{}) (resp interface{}, err error) {
	var options AttachDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "InstanceId":
			instanceID, _ := value.(string)
			options.InstanceID = instanceID
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		case "DeleteWithInstance":
			switch value.(type) {
			case bool:
				options.DeleteWithInstance = value.(bool)
			case string:
				options.DeleteWithInstance = value.(string) == "true" || value.(string) == "True"
			}
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("AttachDisk", params, response)
	resp = response
	return resp, err
}

// Detachdisk detach ECS-Disk from ECS, accept map[string]interface{}
func (aliStorage *Alistorage) Detachdisk(request interface{}) (resp interface{}, err error) {
	var options AttachDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "InstanceId":
			instanceId, _ := value.(string)
			options.InstanceID = instanceId
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("DetachDisk", params, response)
	resp = response
	return resp, err
}
<commit_msg>Ali storage: improve code suggested by codacy<commit_after>package alistorage

import (
	"strconv"
	"github.com/cloudlibz/gocloud/aliauth"
)

// Createdisk create ECS-Disk accept map[string]interface{}
func (aliStorage *Alistorage) Createdisk(request interface{}) (resp interface{}, err error) {
	var options CreateDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "RegionId":
			regionID, _ := value.(string)
			options.RegionID = regionID
		case "ZoneId":
			zoneID, _ := value.(string)
			options.ZoneID = zoneID
		case "DiskName":
			diskName, _ := value.(string)
			options.DiskName = diskName
		case "Description":
			description, _ := value.(string)
			options.Description = description
		case "Encrypted":
			switch value.(type) {
			case bool:
				options.Encrypted = value.(bool)
			case string:
				options.Encrypted = value.(string) == "true" || value.(string) == "True"
			}
		case "DiskCategory":
			diskCategory, _ := value.(string)
			options.DiskCategory = diskCategory
		case "Size":
			switch value.(type) {
			case int:
				options.Size = value.(int)
			case string:
				options.Size, _ = strconv.Atoi(value.(string))
			}
		case "SnapshotId":
			snapshotID, _ := value.(string)
			options.SnapshotID = snapshotID
		case "ClientToken":
			clientToken, _ := value.(string)
			options.ClientToken = clientToken
		}
	}

	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("CreateDisk", params, response)
	resp = response
	return resp, err
}

// Deletedisk delete ECS-Disk accept map[string]interface{}
func (aliStorage *Alistorage) Deletedisk(request interface{}) (resp interface{}, err error) {
	var options DeleteDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("DeleteDisk", params, response)
	resp = response
	return resp, err
}

//TODO
func (aliStorage *Alistorage) Createsnapshot(request interface{}) (resp interface{}, err error) {
	return resp, err
}

//TODO
func (aliStorage *Alistorage) Deletesnapshot(request interface{}) (resp interface{}, err error) {
	return resp, err
}

// Attachdisk attach ECS-Disk to ECS, accept map[string]interface{}
func (aliStorage *Alistorage) Attachdisk(request interface{}) (resp interface{}, err error) {
	var options AttachDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "InstanceId":
			instanceID, _ := value.(string)
			options.InstanceID = instanceID
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		case "DeleteWithInstance":
			switch value.(type) {
			case bool:
				options.DeleteWithInstance = value.(bool)
			case string:
				options.DeleteWithInstance = value.(string) == "true" || value.(string) == "True"
			}
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("AttachDisk", params, response)
	resp = response
	return resp, err
}

// Detachdisk detach ECS-Disk from ECS, accept map[string]interface{}
func (aliStorage *Alistorage) Detachdisk(request interface{}) (resp interface{}, err error) {
	var options AttachDisk

	param := make(map[string]interface{})

	param = request.(map[string]interface{})

	for key, value := range param {
		switch key {
		case "InstanceId":
			instanceID, _ := value.(string)
			options.InstanceID = instanceID
		case "DiskId":
			diskID, _ := value.(string)
			options.DiskID = diskID
		}
	}
	// Put all of options into params
	params := aliauth.PutStructToMap(&options)

	response := make(map[string]interface{})
	err = aliauth.SignAndDoRequest("DetachDisk", params, response)
	resp = response
	return resp, err
}
<|endoftext|>


<commit_before>package aws

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/sirupsen/logrus"
)

type logrusProxy struct {
	logger *logrus.Logger
}

func (proxy *logrusProxy) Log(args ...interface{}) {
	proxy.logger.Info(args...)
}

// NewSessionWithConfig returns an awsSession that includes the user supplied
// configuration information
func NewSessionWithConfig(awsConfig *aws.Config, logger *logrus.Logger) *session.Session {
	return NewSessionWithConfigLevel(awsConfig, aws.LogDebugWithRequestErrors, logger)
}

// NewSession that attaches a debug level handler to all AWS requests from services
// sharing the session value.
func NewSession(logger *logrus.Logger) *session.Session {
	return NewSessionWithLevel(aws.LogDebugWithRequestErrors, logger)
}

// NewSessionWithLevel returns an AWS Session (https://github.com/aws/aws-sdk-go/wiki/Getting-Started-Configuration)
// object that attaches a debug level handler to all AWS requests from services
// sharing the session value.
func NewSessionWithLevel(level aws.LogLevelType, logger *logrus.Logger) *session.Session {
	awsConfig := &aws.Config{
		CredentialsChainVerboseErrors: aws.Bool(true),
	}
	return NewSessionWithConfigLevel(awsConfig, level, logger)
}

// NewSessionWithConfigLevel returns an AWS Session (https://github.com/aws/aws-sdk-go/wiki/Getting-Started-Configuration)
// object that attaches a debug level handler to all AWS requests from services
// sharing the session value.
func NewSessionWithConfigLevel(awsConfig *aws.Config,
	level aws.LogLevelType,
	logger *logrus.Logger) *session.Session {
	if nil == awsConfig {
		awsConfig = &aws.Config{
			CredentialsChainVerboseErrors: aws.Bool(true),
		}
	}

	// Log AWS calls if needed
	switch logger.Level {
	case logrus.DebugLevel:
		awsConfig.LogLevel = aws.LogLevel(level)
	}
	awsConfig.Logger = &logrusProxy{logger}
	sess := session.New(awsConfig)
	sess.Handlers.Send.PushFront(func(r *request.Request) {
		logger.WithFields(logrus.Fields{
			"Service":   r.ClientInfo.ServiceName,
			"Operation": r.Operation.Name,
			"Method":    r.Operation.HTTPMethod,
			"Path":      r.Operation.HTTPPath,
			"Payload":   r.Params,
		}).Debug("AWS Request")
	})

	logger.WithFields(logrus.Fields{
		"Name":    aws.SDKName,
		"Version": aws.SDKVersion,
	}).Debug("AWS SDK Info")
	return sess
}
<commit_msg>Function comment<commit_after>package aws

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/sirupsen/logrus"
)

type logrusProxy struct {
	logger *logrus.Logger
}

// Log is a utility function to comply with the AWS signature
func (proxy *logrusProxy) Log(args ...interface{}) {
	proxy.logger.Info(args...)
}

// NewSessionWithConfig returns an awsSession that includes the user supplied
// configuration information
func NewSessionWithConfig(awsConfig *aws.Config, logger *logrus.Logger) *session.Session {
	return NewSessionWithConfigLevel(awsConfig, aws.LogDebugWithRequestErrors, logger)
}

// NewSession that attaches a debug level handler to all AWS requests from services
// sharing the session value.
func NewSession(logger *logrus.Logger) *session.Session {
	return NewSessionWithLevel(aws.LogDebugWithRequestErrors, logger)
}

// NewSessionWithLevel returns an AWS Session (https://github.com/aws/aws-sdk-go/wiki/Getting-Started-Configuration)
// object that attaches a debug level handler to all AWS requests from services
// sharing the session value.
func NewSessionWithLevel(level aws.LogLevelType, logger *logrus.Logger) *session.Session {
	awsConfig := &aws.Config{
		CredentialsChainVerboseErrors: aws.Bool(true),
	}
	return NewSessionWithConfigLevel(awsConfig, level, logger)
}

// NewSessionWithConfigLevel returns an AWS Session (https://github.com/aws/aws-sdk-go/wiki/Getting-Started-Configuration)
// object that attaches a debug level handler to all AWS requests from services
// sharing the session value.
func NewSessionWithConfigLevel(awsConfig *aws.Config,
	level aws.LogLevelType,
	logger *logrus.Logger) *session.Session {
	if nil == awsConfig {
		awsConfig = &aws.Config{
			CredentialsChainVerboseErrors: aws.Bool(true),
		}
	}

	// Log AWS calls if needed
	switch logger.Level {
	case logrus.DebugLevel:
		awsConfig.LogLevel = aws.LogLevel(level)
	}
	awsConfig.Logger = &logrusProxy{logger}
	sess := session.New(awsConfig)
	sess.Handlers.Send.PushFront(func(r *request.Request) {
		logger.WithFields(logrus.Fields{
			"Service":   r.ClientInfo.ServiceName,
			"Operation": r.Operation.Name,
			"Method":    r.Operation.HTTPMethod,
			"Path":      r.Operation.HTTPPath,
			"Payload":   r.Params,
		}).Debug("AWS Request")
	})

	logger.WithFields(logrus.Fields{
		"Name":    aws.SDKName,
		"Version": aws.SDKVersion,
	}).Debug("AWS SDK Info")
	return sess
}
<|endoftext|>


<commit_before>// Package for copying between memory ranges managed by C code and Go Buffers
package coffer

import os "os"
import "unsafe"
import "fmt"

// #include <stdlib.h>
// #include <string.h>
import "C"

// A Coffer implements the io.ReadWriteSeeker interface for
// a memory range
//
// This allows direct copying between a C memory range
// and a Go Buffer
//
// This struct is not thread-safe
//
type Coffer struct {
  base uintptr // base pointer
  seek uintptr // current pointer
  stop uintptr // pointer to last element
}

// Creates a new Coffer that allows reading the continous memory range between
// basePtr and basePtr + sz
//
// returns nil, os.EINVAL if basePtr is 0 or sz <= 0
//
func NewCoffer(base_ uintptr, sz int) (coffer *Coffer, err os.Error) {
	// base == 0 is interpreted as closed state
  if base_ == uintptr(0) {
    return nil, os.EINVAL
  }

	// sz must be positive
  if sz <= 0 {
    coffer = nil
    err = os.EINVAL
    return
  }

	seek_ := base_
  stop_ := uintptr(base_) + uintptr(sz - 1)

  return &Coffer{base: base_, seek: seek_, stop: stop_}, nil
}

func (p *Coffer) String() string {
	return fmt.Sprintf("&{base: %p, seek: %p, stop: %p} /* open := %t ; eof := %t; tell := %v; cap := %v */ ", p.base, p.seek, p.stop, p.IsOpen(), p.IsEOF(), p.Tell(), p.Cap())
}

// Current Seek position
//
func (p *Coffer) Tell() int64 {
	if (p.IsEOF()) { return int64(p.Cap()) }
	return int64(p.seek - p.base)
}

// Cap() - 1
func (p *Coffer) Diff() int { return int(p.stop - p.base) }

// Cap of the managed range, always >= 1
func (p *Coffer) Cap() int { return int(p.stop - p.base) + 1 }

// Remaing bytes to be read or written
func (p *Coffer) Len() int {
	if (p.Contains(p.seek)) {
		return int(p.stop - p.seek) + 1
	}
	return 0
}

// true, iff EOF was enountered during a previous Read() or Write() call
//
// Seek() resets to false
func (p *Coffer) IsEOF() bool { return (p.seek == uintptr(0)) }

// true, iff offset is contained in managed memory range
func (p *Coffer) ContainsOffset(offset int64) bool {
  return offset >= 0 && offset <= int64(p.Diff())
}

// panic(os.EINVAL) iff offset is not contained in managed memory range
func (p *Coffer) EnsureContainsOffset(offset int64) {
  if p.ContainsOffset(offset) {
    return
  }
  // else
  panic(os.EINVAL)
}

// true iff pos is contained in memory range
func (p *Coffer) Contains(pos uintptr) bool {
  return (pos >= p.base && pos <= p.stop)
}

// panic(os.EINVAL) iff pos is not contained in memory range
func (p *Coffer) EnsureContains(pos uintptr) {
  if p.Contains(pos) {
    return
  }
  // else
  panic(os.EINVAL)
}

// Compute an absolute seek position within this Coffer
// (Parameters as in io.Seek)
//
// returns int64(p.seek), os.EINVAL iff whence is not in 0..2
func (p *Coffer) SeekPos(whence int, offset int64) (ret int64, err os.Error) {
  var newOffset int64
  switch whence {
  default:
    return p.Tell(), os.EINVAL
  case 0:
    newOffset = offset
  case 1:
    newOffset = p.Tell() + offset
  case 2:
    newOffset = int64(p.Diff()) + offset
  }
  return newOffset, nil
}

// If offset points outside the underlying managed memory range
// returns p.seek, os.EINVAL
//
// If !p.IsOpen() returns p.seek, os.EINVAL
func (p *Coffer) Seek(whence int, offset int64) (ret int64, err os.Error) {
  if !p.IsOpen() {
    return int64(p.seek), os.EINVAL
  }
  ret, err = p.SeekPos(whence, offset)
	if (err != nil) { return ret, err }
  p.EnsureContainsOffset(ret)
  p.seek = p.base + uintptr(ret)
  return
}

func (p *Coffer) Read(dst []uint8) (n int, err os.Error) {
  // Bail out if EOF was hit before
  if !p.IsOpen() || p.IsEOF() {
    return 0, os.EOF
  }

  // Ensure copy only if dstLen > 0
  dstLen := len(dst)
  if dstLen == 0 {
    return 0, os.EINVAL
  }

  // Ensures copy only if srcLen > 0
  srcLen := p.Len()
  if srcLen == 0 {
    return 0, os.EINVAL
  }

  // Copy min(dstLen, srcLen) > 0 bytes
  srcPtr := unsafe.Pointer(p.seek)
  dstPtr := unsafe.Pointer(&dst[0])
  if srcLen > dstLen {
    C.memmove(dstPtr, srcPtr, C.size_t(dstLen))
    p.seek = p.seek + uintptr(dstLen)
    return int(dstLen), nil
  }
  // else srcLen <= dstLen
  C.memmove(dstPtr, srcPtr, C.size_t(srcLen))
	// Mark EOF
  p.seek = uintptr(0)
  return int(srcLen), os.EOF
}

// Will not append but instead stop with EOF at end of range
func (p *Coffer) Write(src []uint8) (n int, err os.Error) {

  // Bail out if EOF was hit before
  if !p.IsOpen() || p.IsEOF() {
    return 0, os.EOF
  }

  // Ensure copy only if srcLen > 0
  // assumes sizeof(uintptr) >= sizeof(int) which is the case
  srcLen := len(src)
  if srcLen == 0 {
    return 0, os.EINVAL
  }

  // Ensures copy only if dstLen > 0
  dstLen := p.Len()
  if dstLen == 0 {
    return 0, os.EINVAL
  }

  // Copy min(dstLen, srcLen) > 0 bytes
  srcPtr := unsafe.Pointer(&src[0])
  dstPtr := unsafe.Pointer(p.seek)
  if srcLen >= dstLen {
    C.memmove(dstPtr, srcPtr, C.size_t(dstLen))
		// Mark EOF
  	p.seek = uintptr(0)
    return int(dstLen), os.EOF
  }
  // else srcLen < dstLen
  C.memmove(dstPtr, srcPtr, C.size_t(srcLen))
  p.seek = p.seek + uintptr(srcLen)
  return int(srcLen), nil
}

func (p *Coffer) IsOpen() bool {
	return (p.base != uintptr(0))
}

// Closes this coffer by zeroing all internal fields
//
// Cant Read() or Write() or Seek() anymore afterwards
//
// Does not free any managed pointers
func (p *Coffer) Close() os.Error {
  // Zero ptrs to avoid any lingering harm
  p.base = uintptr(0)
  p.seek = uintptr(0)
  p.stop = uintptr(0)
  return nil
}

// {}
<commit_msg>make format<commit_after>// Package for copying between memory ranges managed by C code and Go Buffers
package coffer

import os "os"
import "unsafe"
import "fmt"

// #include <stdlib.h>
// #include <string.h>
import "C"

// A Coffer implements the io.ReadWriteSeeker interface for
// a memory range
//
// This allows direct copying between a C memory range
// and a Go Buffer
//
// This struct is not thread-safe
//
type Coffer struct {
  base uintptr // base pointer
  seek uintptr // current pointer
  stop uintptr // pointer to last element
}

// Creates a new Coffer that allows reading the continous memory range between
// basePtr and basePtr + sz
//
// returns nil, os.EINVAL if basePtr is 0 or sz <= 0
//
func NewCoffer(base_ uintptr, sz int) (coffer *Coffer, err os.Error) {
  // base == 0 is interpreted as closed state
  if base_ == uintptr(0) {
    return nil, os.EINVAL
  }

  // sz must be positive
  if sz <= 0 {
    coffer = nil
    err = os.EINVAL
    return
  }

  seek_ := base_
  stop_ := uintptr(base_) + uintptr(sz-1)

  return &Coffer{base: base_, seek: seek_, stop: stop_}, nil
}

func (p *Coffer) String() string {
  return fmt.Sprintf("&{base: %p, seek: %p, stop: %p} /* open := %t ; eof := %t; tell := %v; cap := %v */ ", p.base, p.seek, p.stop, p.IsOpen(), p.IsEOF(), p.Tell(), p.Cap())
}

// Current Seek position
//
func (p *Coffer) Tell() int64 {
  if p.IsEOF() {
    return int64(p.Cap())
  }
  return int64(p.seek - p.base)
}

// Cap() - 1
func (p *Coffer) Diff() int { return int(p.stop - p.base) }

// Cap of the managed range, always >= 1
func (p *Coffer) Cap() int { return int(p.stop-p.base) + 1 }

// Remaing bytes to be read or written
func (p *Coffer) Len() int {
  if p.Contains(p.seek) {
    return int(p.stop-p.seek) + 1
  }
  return 0
}

// true, iff EOF was enountered during a previous Read() or Write() call
//
// Seek() resets to false
func (p *Coffer) IsEOF() bool { return (p.seek == uintptr(0)) }

// true, iff offset is contained in managed memory range
func (p *Coffer) ContainsOffset(offset int64) bool {
  return offset >= 0 && offset <= int64(p.Diff())
}

// panic(os.EINVAL) iff offset is not contained in managed memory range
func (p *Coffer) EnsureContainsOffset(offset int64) {
  if p.ContainsOffset(offset) {
    return
  }
  // else
  panic(os.EINVAL)
}

// true iff pos is contained in memory range
func (p *Coffer) Contains(pos uintptr) bool {
  return (pos >= p.base && pos <= p.stop)
}

// panic(os.EINVAL) iff pos is not contained in memory range
func (p *Coffer) EnsureContains(pos uintptr) {
  if p.Contains(pos) {
    return
  }
  // else
  panic(os.EINVAL)
}

// Compute an absolute seek position within this Coffer
// (Parameters as in io.Seek)
//
// returns int64(p.seek), os.EINVAL iff whence is not in 0..2
func (p *Coffer) SeekPos(whence int, offset int64) (ret int64, err os.Error) {
  var newOffset int64
  switch whence {
  default:
    return p.Tell(), os.EINVAL
  case 0:
    newOffset = offset
  case 1:
    newOffset = p.Tell() + offset
  case 2:
    newOffset = int64(p.Diff()) + offset
  }
  return newOffset, nil
}

// If offset points outside the underlying managed memory range
// returns p.seek, os.EINVAL
//
// If !p.IsOpen() returns p.seek, os.EINVAL
func (p *Coffer) Seek(whence int, offset int64) (ret int64, err os.Error) {
  if !p.IsOpen() {
    return int64(p.seek), os.EINVAL
  }
  ret, err = p.SeekPos(whence, offset)
  if err != nil {
    return ret, err
  }
  p.EnsureContainsOffset(ret)
  p.seek = p.base + uintptr(ret)
  return
}

func (p *Coffer) Read(dst []uint8) (n int, err os.Error) {
  // Bail out if EOF was hit before
  if !p.IsOpen() || p.IsEOF() {
    return 0, os.EOF
  }

  // Ensure copy only if dstLen > 0
  dstLen := len(dst)
  if dstLen == 0 {
    return 0, os.EINVAL
  }

  // Ensures copy only if srcLen > 0
  srcLen := p.Len()
  if srcLen == 0 {
    return 0, os.EINVAL
  }

  // Copy min(dstLen, srcLen) > 0 bytes
  srcPtr := unsafe.Pointer(p.seek)
  dstPtr := unsafe.Pointer(&dst[0])
  if srcLen > dstLen {
    C.memmove(dstPtr, srcPtr, C.size_t(dstLen))
    p.seek = p.seek + uintptr(dstLen)
    return int(dstLen), nil
  }
  // else srcLen <= dstLen
  C.memmove(dstPtr, srcPtr, C.size_t(srcLen))
  // Mark EOF
  p.seek = uintptr(0)
  return int(srcLen), os.EOF
}

// Will not append but instead stop with EOF at end of range
func (p *Coffer) Write(src []uint8) (n int, err os.Error) {

  // Bail out if EOF was hit before
  if !p.IsOpen() || p.IsEOF() {
    return 0, os.EOF
  }

  // Ensure copy only if srcLen > 0
  // assumes sizeof(uintptr) >= sizeof(int) which is the case
  srcLen := len(src)
  if srcLen == 0 {
    return 0, os.EINVAL
  }

  // Ensures copy only if dstLen > 0
  dstLen := p.Len()
  if dstLen == 0 {
    return 0, os.EINVAL
  }

  // Copy min(dstLen, srcLen) > 0 bytes
  srcPtr := unsafe.Pointer(&src[0])
  dstPtr := unsafe.Pointer(p.seek)
  if srcLen >= dstLen {
    C.memmove(dstPtr, srcPtr, C.size_t(dstLen))
    // Mark EOF
    p.seek = uintptr(0)
    return int(dstLen), os.EOF
  }
  // else srcLen < dstLen
  C.memmove(dstPtr, srcPtr, C.size_t(srcLen))
  p.seek = p.seek + uintptr(srcLen)
  return int(srcLen), nil
}

func (p *Coffer) IsOpen() bool {
  return (p.base != uintptr(0))
}

// Closes this coffer by zeroing all internal fields
//
// Cant Read() or Write() or Seek() anymore afterwards
//
// Does not free any managed pointers
func (p *Coffer) Close() os.Error {
  // Zero ptrs to avoid any lingering harm
  p.base = uintptr(0)
  p.seek = uintptr(0)
  p.stop = uintptr(0)
  return nil
}

// {}
<|endoftext|>


<commit_before>// Package for copying between memory ranges managed by C code and Go Buffers
package coffer

import os "os"
import .  "gonewrong"
import "unsafe"
import "fmt"
import "io"

// #include <stdlib.h>
// #include <string.h>
import "C"

// A PtrCoffer implements the io.ReadWriteSeeker interface for
// a memory range
//
// This allows direct copying between a C memory range
// and a Go Buffer
type Coffer interface {
    io.ReadWriteSeeker
    io.Closer
}

// Plain coffer on some memory range provided by the user
//
// This struct is not thread-safe
//
type PtrCoffer struct {
    base uintptr // base pointer
    seek uintptr // current pointer
    stop uintptr // pointer to last element
}

// Creates a new PtrCoffer that allows reading the continous memory range
// between basePtr and basePtr + sz
//
// returns nil, os.EINVAL if basePtr is 0 or sz <= 0
//
func NewPtrCoffer(base_ uintptr, sz int) (coffer *PtrCoffer, err os.Error) {
    // base == 0 is interpreted as closed state
    if base_ == uintptr(0) {
        return nil, os.EINVAL
    }

    // sz must be positive
    if sz <= 0 {
        coffer = nil
        err = os.EINVAL
        return
    }

    seek_ := base_
    stop_ := uintptr(base_) + uintptr(sz-1)

    return &PtrCoffer{base: base_, seek: seek_, stop: stop_}, nil
}

func (p *PtrCoffer) InitPtrCoffer(base_ uintptr, sz int) os.Error {
    // base == 0 is interpreted as closed state
    if base_ == uintptr(0) {
        return os.EINVAL
    }

    // sz must be positive
    if sz <= 0 {
        return os.EINVAL
    }

    if p.IsOpen() {
        return os.EINVAL
    }

    p.base = base_
    p.seek = base_
    p.stop = uintptr(base_) + uintptr(sz-1)

    return nil
}

func (p *PtrCoffer) String() string {
    return fmt.Sprintf("&{base: %p, seek: %p, stop: %p} /* open := %t ; eof := %t; tell := %v; cap := %v */ ", p.base, p.seek, p.stop, p.IsOpen(), p.IsEOF(), p.Tell(), p.Cap())
}

// Current Seek position
func (p *PtrCoffer) Tell() int64 {
    if p.IsEOF() {
        return int64(p.Cap())
    }
    return int64(p.seek - p.base)
}

// Cap() - 1
func (p *PtrCoffer) Diff() int {
    return int(p.stop - p.base)
}

// Cap of the managed range, always >= 1
func (p *PtrCoffer) Cap() int {
    return int(p.stop-p.base) + 1
}

// Remaing bytes to be read or written
func (p *PtrCoffer) Len() int {
    if p.IsOpen() && !p.IsEOF() {
        return int(p.stop-p.seek) + 1
    }
    return 0
}

// true, iff EOF was encountered during a previous Read() or Write() call
//
// Seek() resets to false
func (p *PtrCoffer) IsEOF() bool {
    return (p.seek == uintptr(0))
}

// true, iff offset is contained in managed memory range
func (p *PtrCoffer) ContainsOffset(offset int64) bool {
    return offset >= 0 && offset <= int64(p.Diff())
}

// panic(os.EINVAL) iff offset is not contained in managed memory range
func (p *PtrCoffer) EnsureContainsOffset(offset int64) {
    if p.ContainsOffset(offset) {
        return
    }
    // else
    panic(os.EINVAL)
}

// true iff pos is contained in memory range
func (p *PtrCoffer) Contains(pos uintptr) bool {
    return (pos >= p.base && pos <= p.stop)
}

// panic(os.EINVAL) iff pos is not contained in memory range
func (p *PtrCoffer) EnsureContains(pos uintptr) {
    if p.Contains(pos) {
        return
    }
    // else
    panic(os.EINVAL)
}

// Compute an absolute seek position within this PtrCoffer
// (Parameters as in io.Seek)
//
// returns int64(p.seek), os.EINVAL iff whence is not in 0..2
func (p *PtrCoffer) SeekPos(offset int64, whence int) (ret int64, err os.Error) {
    var newOffset int64
    switch whence {
    default:
        return p.Tell(), os.EINVAL
    case 0:
        newOffset = offset
    case 1:
        newOffset = p.Tell() + offset
    case 2:
        newOffset = int64(p.Diff()) + offset
    }
    return newOffset, nil
}

// If offset points outside the underlying managed memory range
// returns p.seek, os.EINVAL
//
// If !p.IsOpen() returns p.seek, os.EINVAL
func (p *PtrCoffer) Seek(offset int64, whence int) (ret int64, err os.Error) {
    if !p.IsOpen() {
        return int64(p.seek), os.EINVAL
    }
    ret, err = p.SeekPos(offset, whence)
    if err != nil {
        return ret, err
    }
    p.EnsureContainsOffset(ret)
    p.seek = p.base + uintptr(ret)
    return
}

func (p *PtrCoffer) Read(dst []uint8) (n int, err os.Error) {
    // Bail out if EOF was hit before
    if !p.IsOpen() || p.IsEOF() {
        return 0, os.EOF
    }

    // Ensure copy only if dstLen > 0
    dstLen := len(dst)
    if dstLen == 0 {
        return 0, os.EINVAL
    }

    // Ensures copy only if srcLen > 0
    srcLen := p.Len()
    if srcLen == 0 {
        return 0, os.EINVAL
    }

    // Copy min(dstLen, srcLen) > 0 bytes
    srcPtr := unsafe.Pointer(p.seek)
    dstPtr := unsafe.Pointer(&dst[0])
    if srcLen > dstLen {
        C.memmove(dstPtr, srcPtr, C.size_t(dstLen))
        p.seek = p.seek + uintptr(dstLen)
        return int(dstLen), nil
    }
    // else srcLen <= dstLen
    C.memmove(dstPtr, srcPtr, C.size_t(srcLen))
    // Mark EOF
    p.seek = uintptr(0)
    return int(srcLen), os.EOF
}

// Will not append but instead stop with EOF at end of range
func (p *PtrCoffer) Write(src []uint8) (n int, err os.Error) {

    // Bail out if EOF was hit before
    if !p.IsOpen() || p.IsEOF() {
        return 0, os.EOF
    }

    // Ensure copy only if srcLen > 0
    // assumes sizeof(uintptr) >= sizeof(int) which is the case
    srcLen := len(src)
    if srcLen == 0 {
        return 0, os.EINVAL
    }

    // Ensures copy only if dstLen > 0
    dstLen := p.Len()
    if dstLen == 0 {
        return 0, os.EINVAL
    }

    // Copy min(dstLen, srcLen) > 0 bytes
    srcPtr := unsafe.Pointer(&src[0])
    dstPtr := unsafe.Pointer(p.seek)
    if srcLen >= dstLen {
        C.memmove(dstPtr, srcPtr, C.size_t(dstLen))
        // Mark EOF
        p.seek = uintptr(0)
        return int(dstLen), os.EOF
    }
    // else srcLen < dstLen
    C.memmove(dstPtr, srcPtr, C.size_t(srcLen))
    p.seek = p.seek + uintptr(srcLen)
    return int(srcLen), nil
}

func (p *PtrCoffer) IsOpen() bool {
    return (p.base != uintptr(0))
}

// Closes this coffer by zeroing all internal fields
//
// Cant Read() or Write() or Seek() anymore afterwards
//
// Does not free any managed pointers
func (p *PtrCoffer) Close() os.Error {
    // Zero ptrs to avoid any lingering harm
    p.base = uintptr(0)
    p.seek = uintptr(0)
    p.stop = uintptr(0)
    return nil
}

// Selfallocating coffer via malloc, frees on Close()
type MemCoffer struct {
    PtrCoffer
}

// Allocate a coffer independent from the go runtime, i.e.
// you are responsible for freeing its mem content
// by calling Close() (You get memory leaks iff you don't)
func NewMemCoffer(sz int) (coffer Coffer, err os.Error) {
    if sz < 0 {
        return nil, os.EINVAL
    }
    base_ := uintptr(C.malloc(C.size_t(sz)))
    if IsCNullPtr(base_) {
        return nil, os.Errno(GetCErrno())
    }
    seek_ := base_
    stop_ := uintptr(base_) + uintptr(sz-1)

    cf := new(MemCoffer)
    cf.base = base_
    cf.seek = seek_
    cf.stop = stop_
    coffer = cf
    return coffer, nil
}

func (p *MemCoffer) Close() os.Error {
    if p.IsEOF() {
        return os.EOF
    }
    // Free memory in defer
    backup := unsafe.Pointer(p.base)
    defer C.free(backup)

    // Zero ptrs to avoid any lingering harm
    p.base = uintptr(0)
    p.seek = uintptr(0)
    p.stop = uintptr(0)
    return nil
}

// {}
<commit_msg>Added getters for internal pointers to public Coffer interface<commit_after>// Package for copying between memory ranges managed by C code and Go Buffers
package coffer

import os "os"
import .  "gonewrong"
import "unsafe"
import "fmt"
import "io"

// #include <stdlib.h>
// #include <string.h>
import "C"

// A PtrCoffer implements the io.ReadWriteSeeker interface for
// a memory range
//
// This allows direct copying between a C memory range
// and a Go Buffer
type Coffer interface {
    io.ReadWriteSeeker
    io.Closer

	GetBasePtr() uintptr
	GetSeekPtr() uintptr
	GetStopPtr() uintptr
}

// Plain coffer on some memory range provided by the user
//
// This struct is not thread-safe
//
type PtrCoffer struct {
    base uintptr // base pointer
    seek uintptr // current pointer
    stop uintptr // pointer to last element
}

// Creates a new PtrCoffer that allows reading the continous memory range
// between basePtr and basePtr + sz
//
// returns nil, os.EINVAL if basePtr is 0 or sz <= 0
//
func NewPtrCoffer(base_ uintptr, sz int) (coffer *PtrCoffer, err os.Error) {
    // base == 0 is interpreted as closed state
    if base_ == uintptr(0) {
        return nil, os.EINVAL
    }

    // sz must be positive
    if sz <= 0 {
        coffer = nil
        err = os.EINVAL
        return
    }

    seek_ := base_
    stop_ := uintptr(base_) + uintptr(sz-1)

    return &PtrCoffer{base: base_, seek: seek_, stop: stop_}, nil
}

func (p *PtrCoffer) InitPtrCoffer(base_ uintptr, sz int) os.Error {
    // base == 0 is interpreted as closed state
    if base_ == uintptr(0) {
        return os.EINVAL
    }

    // sz must be positive
    if sz <= 0 {
        return os.EINVAL
    }

    if p.IsOpen() {
        return os.EINVAL
    }

    p.base = base_
    p.seek = base_
    p.stop = uintptr(base_) + uintptr(sz-1)

    return nil
}

func (p *PtrCoffer) String() string {
    return fmt.Sprintf("&{base: %p, seek: %p, stop: %p} /* open := %t ; eof := %t; tell := %v; cap := %v */ ", p.base, p.seek, p.stop, p.IsOpen(), p.IsEOF(), p.Tell(), p.Cap())
}

// Current Seek position
func (p *PtrCoffer) Tell() int64 {
    if p.IsEOF() {
        return int64(p.Cap())
    }
    return int64(p.seek - p.base)
}

// Cap() - 1
func (p *PtrCoffer) Diff() int {
    return int(p.stop - p.base)
}

// Cap of the managed range, always >= 1
func (p *PtrCoffer) Cap() int {
    return int(p.stop-p.base) + 1
}

// Remaing bytes to be read or written
func (p *PtrCoffer) Len() int {
    if p.IsOpen() && !p.IsEOF() {
        return int(p.stop-p.seek) + 1
    }
    return 0
}

// true, iff EOF was encountered during a previous Read() or Write() call
//
// Seek() resets to false
func (p *PtrCoffer) IsEOF() bool {
    return (p.seek == uintptr(0))
}

// true, iff offset is contained in managed memory range
func (p *PtrCoffer) ContainsOffset(offset int64) bool {
    return offset >= 0 && offset <= int64(p.Diff())
}

// panic(os.EINVAL) iff offset is not contained in managed memory range
func (p *PtrCoffer) EnsureContainsOffset(offset int64) {
    if p.ContainsOffset(offset) {
        return
    }
    // else
    panic(os.EINVAL)
}

// true iff pos is contained in memory range
func (p *PtrCoffer) Contains(pos uintptr) bool {
    return (pos >= p.base && pos <= p.stop)
}

// panic(os.EINVAL) iff pos is not contained in memory range
func (p *PtrCoffer) EnsureContains(pos uintptr) {
    if p.Contains(pos) {
        return
    }
    // else
    panic(os.EINVAL)
}

// Compute an absolute seek position within this PtrCoffer
// (Parameters as in io.Seek)
//
// returns int64(p.seek), os.EINVAL iff whence is not in 0..2
func (p *PtrCoffer) SeekPos(offset int64, whence int) (ret int64, err os.Error) {
    var newOffset int64
    switch whence {
    default:
        return p.Tell(), os.EINVAL
    case 0:
        newOffset = offset
    case 1:
        newOffset = p.Tell() + offset
    case 2:
        newOffset = int64(p.Diff()) + offset
    }
    return newOffset, nil
}

// If offset points outside the underlying managed memory range
// returns p.seek, os.EINVAL
//
// If !p.IsOpen() returns p.seek, os.EINVAL
func (p *PtrCoffer) Seek(offset int64, whence int) (ret int64, err os.Error) {
    if !p.IsOpen() {
        return int64(p.seek), os.EINVAL
    }
    ret, err = p.SeekPos(offset, whence)
    if err != nil {
        return ret, err
    }
    p.EnsureContainsOffset(ret)
    p.seek = p.base + uintptr(ret)
    return
}

func (p *PtrCoffer) Read(dst []uint8) (n int, err os.Error) {
    // Bail out if EOF was hit before
    if !p.IsOpen() || p.IsEOF() {
        return 0, os.EOF
    }

    // Ensure copy only if dstLen > 0
    dstLen := len(dst)
    if dstLen == 0 {
        return 0, os.EINVAL
    }

    // Ensures copy only if srcLen > 0
    srcLen := p.Len()
    if srcLen == 0 {
        return 0, os.EINVAL
    }

    // Copy min(dstLen, srcLen) > 0 bytes
    srcPtr := unsafe.Pointer(p.seek)
    dstPtr := unsafe.Pointer(&dst[0])
    if srcLen > dstLen {
        C.memmove(dstPtr, srcPtr, C.size_t(dstLen))
        p.seek = p.seek + uintptr(dstLen)
        return int(dstLen), nil
    }
    // else srcLen <= dstLen
    C.memmove(dstPtr, srcPtr, C.size_t(srcLen))
    // Mark EOF
    p.seek = uintptr(0)
    return int(srcLen), os.EOF
}

// Will not append but instead stop with EOF at end of range
func (p *PtrCoffer) Write(src []uint8) (n int, err os.Error) {

    // Bail out if EOF was hit before
    if !p.IsOpen() || p.IsEOF() {
        return 0, os.EOF
    }

    // Ensure copy only if srcLen > 0
    // assumes sizeof(uintptr) >= sizeof(int) which is the case
    srcLen := len(src)
    if srcLen == 0 {
        return 0, os.EINVAL
    }

    // Ensures copy only if dstLen > 0
    dstLen := p.Len()
    if dstLen == 0 {
        return 0, os.EINVAL
    }

    // Copy min(dstLen, srcLen) > 0 bytes
    srcPtr := unsafe.Pointer(&src[0])
    dstPtr := unsafe.Pointer(p.seek)
    if srcLen >= dstLen {
        C.memmove(dstPtr, srcPtr, C.size_t(dstLen))
        // Mark EOF
        p.seek = uintptr(0)
        return int(dstLen), os.EOF
    }
    // else srcLen < dstLen
    C.memmove(dstPtr, srcPtr, C.size_t(srcLen))
    p.seek = p.seek + uintptr(srcLen)
    return int(srcLen), nil
}

func (p *PtrCoffer) IsOpen() bool {
    return (p.base != uintptr(0))
}

// Closes this coffer by zeroing all internal fields
//
// Cant Read() or Write() or Seek() anymore afterwards
//
// Does not free any managed pointers
func (p *PtrCoffer) Close() os.Error {
    // Zero ptrs to avoid any lingering harm
    p.base = uintptr(0)
    p.seek = uintptr(0)
    p.stop = uintptr(0)
    return nil
}

// Selfallocating coffer via malloc, frees on Close()
type MemCoffer struct {
    PtrCoffer
}

// Allocate a coffer independent from the go runtime, i.e.
// you are responsible for freeing its mem content
// by calling Close() (You get memory leaks iff you don't)
func NewMemCoffer(sz int) (coffer Coffer, err os.Error) {
    if sz < 0 {
        return nil, os.EINVAL
    }
    base_ := uintptr(C.malloc(C.size_t(sz)))
    if IsCNullPtr(base_) {
        return nil, os.Errno(GetCErrno())
    }
    seek_ := base_
    stop_ := uintptr(base_) + uintptr(sz-1)

    cf := new(MemCoffer)
    cf.base = base_
    cf.seek = seek_
    cf.stop = stop_
    coffer = cf
    return coffer, nil
}

func (p *MemCoffer) Close() os.Error {
    if p.IsEOF() {
        return os.EOF
    }
    // Free memory in defer
    backup := unsafe.Pointer(p.base)
    defer C.free(backup)

    // Zero ptrs to avoid any lingering harm
    p.base = uintptr(0)
    p.seek = uintptr(0)
    p.stop = uintptr(0)
    return nil
}

func (p *MemCoffer) GetBasePtr() uintptr {
	return p.base
}

func (p *MemCoffer) GetSeekPtr() uintptr {
	return p.base
}

func (p *MemCoffer) GetStopPtr() uintptr {
	return p.base
}

// {}
<|endoftext|>


<commit_before>package dsc

import "reflect"

type TableColumn struct {
	ColumnName       string `column:"column_name"`
	DataType         string `column:"data_type"`
	DataTypeLength   *int64 `column:"data_type_length"`
	NumericPrecision *int64 `column:"numeric_precision"`
	NumericScale     *int64 `column:"numeric_scale"`
	IsNullable       *bool  `column:"is_nullable"`
	Position         int    `column:"position"`
	scanType         reflect.Type
}

func (c *TableColumn) Name() string {
	return c.ColumnName
}

func (c *TableColumn) Length() (length int64, ok bool) {
	if c.DataTypeLength == nil {
		return 0, false
	}
	return *c.DataTypeLength, true
}

func (c *TableColumn) DecimalSize() (precision, scale int64, ok bool) {
	if c.NumericPrecision == nil || c.NumericScale == nil {
		return 0, 0, false
	}
	return *c.NumericPrecision, *c.NumericScale, true
}

func (c *TableColumn) ScanType() reflect.Type {
	return c.scanType
}

func (c *TableColumn) Nullable() (nullable, ok bool) {
	if c.IsNullable == nil {
		return false, false
	}
	return *c.IsNullable, true
}

// Common type include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", "INT", "BIGINT".
func (c *TableColumn) DatabaseTypeName() string {
	return c.DataType
}

//NewColumn create new TableColumn
func NewColumn(name, typeName string, length, precision, scale *int64, scanType reflect.Type, nullable *bool) Column {
	var result = &TableColumn{
		ColumnName:       name,
		DataType:         typeName,
		DataTypeLength:   length,
		NumericPrecision: precision,
		NumericScale:     scale,
		scanType:         scanType,
		IsNullable:       nullable,
	}
	return result
}

//NewSimpleColumn create simple TableColumn name
func NewSimpleColumn(name, typeName string) Column {
	return &TableColumn{
		ColumnName: name,
		DataType:   typeName,
	}
}
<commit_msg>Changed IsNullable as interface type<commit_after>package dsc

import (
	"github.com/viant/toolbox"
	"reflect"
)

type TableColumn struct {
	ColumnName       string      `column:"column_name"`
	DataType         string      `column:"data_type"`
	DataTypeLength   *int64      `column:"data_type_length"`
	NumericPrecision *int64      `column:"numeric_precision"`
	NumericScale     *int64      `column:"numeric_scale"`
	IsNullable       interface{} `column:"is_nullable"`
	Position         int         `column:"position"`
	scanType         reflect.Type
}

func (c *TableColumn) Name() string {
	return c.ColumnName
}

func (c *TableColumn) Length() (length int64, ok bool) {
	if c.DataTypeLength == nil {
		return 0, false
	}
	return *c.DataTypeLength, true
}

func (c *TableColumn) DecimalSize() (precision, scale int64, ok bool) {
	if c.NumericPrecision == nil || c.NumericScale == nil {
		return 0, 0, false
	}
	return *c.NumericPrecision, *c.NumericScale, true
}

func (c *TableColumn) ScanType() reflect.Type {
	return c.scanType
}

func (c *TableColumn) Nullable() (nullable, ok bool) {
	if c.IsNullable == nil {
		return false, false
	}
	return toolbox.AsBoolean(c.IsNullable), true
}

// Common type include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", "INT", "BIGINT".
func (c *TableColumn) DatabaseTypeName() string {
	return c.DataType
}

//NewColumn create new TableColumn
func NewColumn(name, typeName string, length, precision, scale *int64, scanType reflect.Type, nullable *bool) Column {
	var result = &TableColumn{
		ColumnName:       name,
		DataType:         typeName,
		DataTypeLength:   length,
		NumericPrecision: precision,
		NumericScale:     scale,
		scanType:         scanType,
		IsNullable:       nullable,
	}
	return result
}

//NewSimpleColumn create simple TableColumn name
func NewSimpleColumn(name, typeName string) Column {
	return &TableColumn{
		ColumnName: name,
		DataType:   typeName,
	}
}
<|endoftext|>


<commit_before>package logSys

import (
	"fmt"
	"path/filepath"
	"runtime"
)

var debugMode = false
var colors = true

func SetDebugMode(v bool) {
	debugMode = v
}

func logMsg(msg ...interface{}) (ret string) {
	_, fn, line, _ := runtime.Caller(2)
	fn = filepath.Base(fn)

	ret = fmt.Sprintf("[error] %s:%d ", fn, line)
	ret += fmt.Sprint(msg...)

	return
}

func Println(msg ...interface{}) {
	fmt.Println(logMsg(msg...))
}

func Print(msg ...interface{}) {
	fmt.Print(logMsg(msg...))
}
<commit_msg>Small changes to simplify the code<commit_after>package logSys

import (
	"fmt"
	"path/filepath"
	"runtime"
	"time"
)

type MsgType uint8

const (
	Message MsgType = 0
	Debug   MsgType = 1
	Error   MsgType = 0x80
)

var DebugMode = false

func Println(m MsgType, msg ...interface{}) {
	if m == Debug && !DebugMode {
		return
	}

	var debugInfo string
	var color string
	var prefix string

	switch m {
	case Message:
		color = "\x1b[37m" // White
		prefix = "msg"
	case Debug:
		color = "\x1b[93m" // Light Yellow
		prefix = "debug"
	case Error:
		color = "\x1b[91m" // Light Red
		prefix = "error"
	}

	if DebugMode {
		_, fn, line, _ := runtime.Caller(1)
		fn = filepath.Base(fn)
		debugInfo = fmt.Sprintf("%s:%d ", fn, line)
	}

	fmt.Printf("%s%s [%s] %s%s\033[0;00m\n",
		color,
		time.Now().UTC().Format("2006/01/02 15:04:05"),
		prefix,
		debugInfo,
		fmt.Sprint(msg...))
}
<|endoftext|>


<commit_before>package logger

import (
	"github.com/ian-kent/go-log/appenders"
	"github.com/ian-kent/go-log/levels"
	"strings"
)

type Logger interface {
	Level() levels.LogLevel
	Name() string
	FullName() string
	Enabled() map[levels.LogLevel]bool
	Appender() Appender
	Children() []Logger
	Parent() Logger
	GetLogger(string) Logger
	SetLevel(levels.LogLevel)
	Log(levels.LogLevel, ...interface{})
}

type logger struct {
	Logger
	level    levels.LogLevel
	name     string
	enabled  map[levels.LogLevel]bool
	appender Appender
	children []Logger
	parent   Logger
}

type Appender interface {
	Write(level levels.LogLevel, message string, args ...interface{})
}

func New(name string) Logger {
	l := Logger(&logger{
		level:    levels.DEBUG,
		name:     name,
		enabled:  make(map[levels.LogLevel]bool),
		appender: appenders.Console(),
		children: make([]Logger, 0),
		parent:   nil,
	})
	l.SetLevel(levels.DEBUG)
	return l
}

func unwrap(args ...interface{}) []interface{} {
	head := args[0]
	switch head.(type) {
	case func() (string, []interface{}):
		msg, args := head.(func() (string, []interface{}))()
		args = unwrap(args...)
		return append([]interface{}{msg}, args...)
	case func() []interface{}:
		args = unwrap(head.(func() []interface{})()...)
	case func(...interface{}) []interface{}:
		args = unwrap(head.(func(...interface{}) []interface{})(args[1:]...)...)
	}
	return args
}

func (l *logger) New(name string) Logger {
	lg := Logger(&logger{
		level:    levels.INHERIT,
		name:     name,
		enabled:  make(map[levels.LogLevel]bool),
		appender: nil,
		children: make([]Logger, 0),
		parent:   l,
	})
	l.children = append(l.children, lg)
	return lg
}

func (l *logger) GetLogger(name string) Logger {
	bits := strings.Split(name, ".")

	if l.name == bits[0] {
		if len(bits) == 1 {
			return l
		}

		child := bits[1]
		n := strings.Join(bits[1:], ".")
		for _, c := range l.children {
			if c.Name() == child {
				return c.GetLogger(n)
			}
		}

		lg := l.New(child)
		return lg.GetLogger(n)
	}
	lg := l.New(bits[0])
	return lg.GetLogger(name)
}

func (l *logger) write(level levels.LogLevel, params ...interface{}) {
	a := l.Appender()
	if a != nil {
		a.Write(level, params[0].(string), params[1:]...)
	}
}

func (l *logger) Appender() Appender {
	if a := l.Appender(); a != nil {
		return a
	}
	if a := l.parent.Appender(); a != nil {
		return a
	}
	return nil
}

func (l *logger) Log(level levels.LogLevel, params ...interface{}) {
	if !l.Enabled()[level] {
		return
	}
	l.write(level, unwrap(params...)...)
}

func (l *logger) Level() levels.LogLevel {
	if l.level == levels.INHERIT {
		return l.parent.Level()
	}
	return l.level
}

func (l *logger) Enabled() map[levels.LogLevel]bool {
	if l.level == levels.INHERIT {
		return l.parent.Enabled()
	}
	return l.enabled
}

func (l *logger) Name() string {
	return l.name
}

func (l *logger) FullName() string {
	n := l.name
	if l.parent != nil {
		p := l.parent.FullName()
		if len(p) > 0 {
			n = l.parent.FullName() + "." + n
		}
	}
	return n
}

func (l *logger) SetLevel(level levels.LogLevel) {
	l.level = level
	for k, _ := range levels.LogLevelsToString {
		if k <= level {
			l.enabled[k] = true
		} else {
			l.enabled[k] = false
		}
	}
}

func (l *logger) SetAppender(appender Appender) {
	l.appender = appender
}

func (l *logger) Debug(params ...interface{})   { l.Log(levels.DEBUG, params...) }
func (l *logger) Info(params ...interface{})    { l.Log(levels.INFO, params...) }
func (l *logger) Warn(params ...interface{})    { l.Log(levels.WARN, params...) }
func (l *logger) Error(params ...interface{})   { l.Log(levels.ERROR, params...) }
func (l *logger) Trace(params ...interface{})   { l.Log(levels.TRACE, params...) }
func (l *logger) Printf(params ...interface{})  { l.Log(levels.INFO, params...) }
func (l *logger) Println(params ...interface{}) { l.Log(levels.INFO, params...) }
func (l *logger) Fatalf(params ...interface{})  { l.Log(levels.FATAL, params...) }
<commit_msg>Fix appender bug<commit_after>package logger

import (
	"github.com/ian-kent/go-log/appenders"
	"github.com/ian-kent/go-log/levels"
	"strings"
)

type Logger interface {
	Level() levels.LogLevel
	Name() string
	FullName() string
	Enabled() map[levels.LogLevel]bool
	Appender() Appender
	Children() []Logger
	Parent() Logger
	GetLogger(string) Logger
	SetLevel(levels.LogLevel)
	Log(levels.LogLevel, ...interface{})
}

type logger struct {
	Logger
	level    levels.LogLevel
	name     string
	enabled  map[levels.LogLevel]bool
	appender Appender
	children []Logger
	parent   Logger
}

type Appender interface {
	Write(level levels.LogLevel, message string, args ...interface{})
}

func New(name string) Logger {
	l := Logger(&logger{
		level:    levels.DEBUG,
		name:     name,
		enabled:  make(map[levels.LogLevel]bool),
		appender: appenders.Console(),
		children: make([]Logger, 0),
		parent:   nil,
	})
	l.SetLevel(levels.DEBUG)
	return l
}

func unwrap(args ...interface{}) []interface{} {
	head := args[0]
	switch head.(type) {
	case func() (string, []interface{}):
		msg, args := head.(func() (string, []interface{}))()
		args = unwrap(args...)
		return append([]interface{}{msg}, args...)
	case func() []interface{}:
		args = unwrap(head.(func() []interface{})()...)
	case func(...interface{}) []interface{}:
		args = unwrap(head.(func(...interface{}) []interface{})(args[1:]...)...)
	}
	return args
}

func (l *logger) New(name string) Logger {
	lg := Logger(&logger{
		level:    levels.INHERIT,
		name:     name,
		enabled:  make(map[levels.LogLevel]bool),
		appender: nil,
		children: make([]Logger, 0),
		parent:   l,
	})
	l.children = append(l.children, lg)
	return lg
}

func (l *logger) GetLogger(name string) Logger {
	bits := strings.Split(name, ".")

	if l.name == bits[0] {
		if len(bits) == 1 {
			return l
		}

		child := bits[1]
		n := strings.Join(bits[1:], ".")
		for _, c := range l.children {
			if c.Name() == child {
				return c.GetLogger(n)
			}
		}

		lg := l.New(child)
		return lg.GetLogger(n)
	}
	lg := l.New(bits[0])
	return lg.GetLogger(name)
}

func (l *logger) write(level levels.LogLevel, params ...interface{}) {
	a := l.Appender()
	if a != nil {
		a.Write(level, params[0].(string), params[1:]...)
	}
}

func (l *logger) Appender() Appender {
	if a := l.appender; a != nil {
		return a
	}
	if l.parent != nil {
		if a := l.parent.Appender(); a != nil {
			return a
		}
	}
	return nil
}

func (l *logger) Log(level levels.LogLevel, params ...interface{}) {
	if !l.Enabled()[level] {
		return
	}
	l.write(level, unwrap(params...)...)
}

func (l *logger) Level() levels.LogLevel {
	if l.level == levels.INHERIT {
		return l.parent.Level()
	}
	return l.level
}

func (l *logger) Enabled() map[levels.LogLevel]bool {
	if l.level == levels.INHERIT {
		return l.parent.Enabled()
	}
	return l.enabled
}

func (l *logger) Name() string {
	return l.name
}

func (l *logger) FullName() string {
	n := l.name
	if l.parent != nil {
		p := l.parent.FullName()
		if len(p) > 0 {
			n = l.parent.FullName() + "." + n
		}
	}
	return n
}

func (l *logger) SetLevel(level levels.LogLevel) {
	l.level = level
	for k, _ := range levels.LogLevelsToString {
		if k <= level {
			l.enabled[k] = true
		} else {
			l.enabled[k] = false
		}
	}
}

func (l *logger) SetAppender(appender Appender) {
	l.appender = appender
}

func (l *logger) Debug(params ...interface{})   { l.Log(levels.DEBUG, params...) }
func (l *logger) Info(params ...interface{})    { l.Log(levels.INFO, params...) }
func (l *logger) Warn(params ...interface{})    { l.Log(levels.WARN, params...) }
func (l *logger) Error(params ...interface{})   { l.Log(levels.ERROR, params...) }
func (l *logger) Trace(params ...interface{})   { l.Log(levels.TRACE, params...) }
func (l *logger) Printf(params ...interface{})  { l.Log(levels.INFO, params...) }
func (l *logger) Println(params ...interface{}) { l.Log(levels.INFO, params...) }
func (l *logger) Fatalf(params ...interface{})  { l.Log(levels.FATAL, params...) }
<|endoftext|>


<commit_before>package process

import (
	"bytes"
	"fmt"
	"os"
	"path"
	"strconv"
	"strings"

	linuxproc "github.com/c9s/goprocinfo/linux"

	"github.com/weaveworks/common/fs"
	"github.com/weaveworks/scope/probe/host"
)

type walker struct {
	procRoot string
}

// NewWalker creates a new process Walker.
func NewWalker(procRoot string) Walker {
	return &walker{procRoot: procRoot}
}

func readStats(path string) (ppid, threads int, jiffies, rss, rssLimit uint64, err error) {
	var (
		buf                               []byte
		userJiffies, sysJiffies, rssPages uint64
	)
	buf, err = fs.ReadFile(path)
	if err != nil {
		return
	}
	splits := strings.Fields(string(buf))
	if len(splits) < 25 {
		err = fmt.Errorf("Invalid /proc/PID/stat")
		return
	}
	ppid, err = strconv.Atoi(splits[3])
	if err != nil {
		return
	}
	threads, err = strconv.Atoi(splits[19])
	if err != nil {
		return
	}
	userJiffies, err = strconv.ParseUint(splits[13], 10, 64)
	if err != nil {
		return
	}
	sysJiffies, err = strconv.ParseUint(splits[14], 10, 64)
	if err != nil {
		return
	}
	jiffies = userJiffies + sysJiffies
	rssPages, err = strconv.ParseUint(splits[23], 10, 64)
	if err != nil {
		return
	}
	rss = rssPages * uint64(os.Getpagesize())
	rssLimit, err = strconv.ParseUint(splits[24], 10, 64)
	return
}

func readLimits(path string) (openFilesLimit uint64, err error) {
	buf, err := cachedReadFile(path)
	if err != nil {
		return 0, err
	}
	for _, line := range strings.Split(string(buf), "\n") {
		if strings.HasPrefix(line, "Max open files") {
			splits := strings.Fields(line)
			if len(splits) < 6 {
				return 0, fmt.Errorf("Invalid /proc/PID/limits")
			}
			openFilesLimit, err := strconv.Atoi(splits[3])
			return uint64(openFilesLimit), err
		}
	}
	return 0, nil
}

// Walk walks the supplied directory (expecting it to look like /proc)
// and marshalls the files into instances of Process, which it then
// passes one-by-one to the supplied function. Walk is only made public
// so that is can be tested.
func (w *walker) Walk(f func(Process, Process)) error {
	dirEntries, err := fs.ReadDirNames(w.procRoot)
	if err != nil {
		return err
	}

	for _, filename := range dirEntries {
		pid, err := strconv.Atoi(filename)
		if err != nil {
			continue
		}

		ppid, threads, jiffies, rss, rssLimit, err := readStats(path.Join(w.procRoot, filename, "stat"))
		if err != nil {
			continue
		}

		openFiles, err := fs.ReadDirNames(path.Join(w.procRoot, filename, "fd"))
		if err != nil {
			continue
		}

		openFilesLimit, err := readLimits(path.Join(w.procRoot, filename, "limits"))
		if err != nil {
			continue
		}

		cmdline, name := "", "(unknown)"
		if cmdlineBuf, err := cachedReadFile(path.Join(w.procRoot, filename, "cmdline")); err == nil {
			// like proc, treat name as the first element of command line
			i := bytes.IndexByte(cmdlineBuf, '\000')
			if i == -1 {
				i = len(cmdlineBuf)
			}
			name = string(cmdlineBuf[:i])
			cmdlineBuf = bytes.Replace(cmdlineBuf, []byte{'\000'}, []byte{' '}, -1)
			cmdline = string(cmdlineBuf)
		}

		f(Process{
			PID:            pid,
			PPID:           ppid,
			Name:           name,
			Cmdline:        cmdline,
			Threads:        threads,
			Jiffies:        jiffies,
			RSSBytes:       rss,
			RSSBytesLimit:  rssLimit,
			OpenFilesCount: len(openFiles),
			OpenFilesLimit: openFilesLimit,
		}, Process{})
	}

	return nil
}

var previousStat = linuxproc.CPUStat{}

// GetDeltaTotalJiffies returns the number of jiffies that have passed since it
// was last called.  In that respect, it is side-effect-ful.
func GetDeltaTotalJiffies() (uint64, float64, error) {
	stat, err := linuxproc.ReadStat(host.ProcStat)
	if err != nil {
		return 0, 0.0, err
	}

	var (
		currentStat = stat.CPUStatAll
		prevTotal   = (previousStat.Idle + previousStat.IOWait + previousStat.User +
			previousStat.Nice + previousStat.System + previousStat.IRQ +
			previousStat.SoftIRQ + previousStat.Steal)
		currentTotal = (currentStat.Idle + currentStat.IOWait + currentStat.User +
			currentStat.Nice + currentStat.System + currentStat.IRQ +
			currentStat.SoftIRQ + currentStat.Steal)
	)
	previousStat = currentStat
	return currentTotal - prevTotal, float64(len(stat.CPUStats)) * 100., nil
}
<commit_msg>fall back to /proc/<pid>/comm for process name<commit_after>package process

import (
	"bytes"
	"fmt"
	"os"
	"path"
	"strconv"
	"strings"

	linuxproc "github.com/c9s/goprocinfo/linux"

	"github.com/weaveworks/common/fs"
	"github.com/weaveworks/scope/probe/host"
)

type walker struct {
	procRoot string
}

// NewWalker creates a new process Walker.
func NewWalker(procRoot string) Walker {
	return &walker{procRoot: procRoot}
}

func readStats(path string) (ppid, threads int, jiffies, rss, rssLimit uint64, err error) {
	var (
		buf                               []byte
		userJiffies, sysJiffies, rssPages uint64
	)
	buf, err = fs.ReadFile(path)
	if err != nil {
		return
	}
	splits := strings.Fields(string(buf))
	if len(splits) < 25 {
		err = fmt.Errorf("Invalid /proc/PID/stat")
		return
	}
	ppid, err = strconv.Atoi(splits[3])
	if err != nil {
		return
	}
	threads, err = strconv.Atoi(splits[19])
	if err != nil {
		return
	}
	userJiffies, err = strconv.ParseUint(splits[13], 10, 64)
	if err != nil {
		return
	}
	sysJiffies, err = strconv.ParseUint(splits[14], 10, 64)
	if err != nil {
		return
	}
	jiffies = userJiffies + sysJiffies
	rssPages, err = strconv.ParseUint(splits[23], 10, 64)
	if err != nil {
		return
	}
	rss = rssPages * uint64(os.Getpagesize())
	rssLimit, err = strconv.ParseUint(splits[24], 10, 64)
	return
}

func readLimits(path string) (openFilesLimit uint64, err error) {
	buf, err := cachedReadFile(path)
	if err != nil {
		return 0, err
	}
	for _, line := range strings.Split(string(buf), "\n") {
		if strings.HasPrefix(line, "Max open files") {
			splits := strings.Fields(line)
			if len(splits) < 6 {
				return 0, fmt.Errorf("Invalid /proc/PID/limits")
			}
			openFilesLimit, err := strconv.Atoi(splits[3])
			return uint64(openFilesLimit), err
		}
	}
	return 0, nil
}

// Walk walks the supplied directory (expecting it to look like /proc)
// and marshalls the files into instances of Process, which it then
// passes one-by-one to the supplied function. Walk is only made public
// so that is can be tested.
func (w *walker) Walk(f func(Process, Process)) error {
	dirEntries, err := fs.ReadDirNames(w.procRoot)
	if err != nil {
		return err
	}

	for _, filename := range dirEntries {
		pid, err := strconv.Atoi(filename)
		if err != nil {
			continue
		}

		ppid, threads, jiffies, rss, rssLimit, err := readStats(path.Join(w.procRoot, filename, "stat"))
		if err != nil {
			continue
		}

		openFiles, err := fs.ReadDirNames(path.Join(w.procRoot, filename, "fd"))
		if err != nil {
			continue
		}

		openFilesLimit, err := readLimits(path.Join(w.procRoot, filename, "limits"))
		if err != nil {
			continue
		}

		cmdline, name := "", ""
		if cmdlineBuf, err := cachedReadFile(path.Join(w.procRoot, filename, "cmdline")); err == nil {
			// like proc, treat name as the first element of command line
			i := bytes.IndexByte(cmdlineBuf, '\000')
			if i == -1 {
				i = len(cmdlineBuf)
			}
			name = string(cmdlineBuf[:i])
			cmdlineBuf = bytes.Replace(cmdlineBuf, []byte{'\000'}, []byte{' '}, -1)
			cmdline = string(cmdlineBuf)
		}
		if name == "" {
			if commBuf, err := cachedReadFile(path.Join(w.procRoot, filename, "comm")); err == nil {
				name = "[" + strings.TrimSpace(string(commBuf)) + "]"
			} else {
				name = "(unknown)"
			}
		}
		f(Process{
			PID:            pid,
			PPID:           ppid,
			Name:           name,
			Cmdline:        cmdline,
			Threads:        threads,
			Jiffies:        jiffies,
			RSSBytes:       rss,
			RSSBytesLimit:  rssLimit,
			OpenFilesCount: len(openFiles),
			OpenFilesLimit: openFilesLimit,
		}, Process{})
	}

	return nil
}

var previousStat = linuxproc.CPUStat{}

// GetDeltaTotalJiffies returns the number of jiffies that have passed since it
// was last called.  In that respect, it is side-effect-ful.
func GetDeltaTotalJiffies() (uint64, float64, error) {
	stat, err := linuxproc.ReadStat(host.ProcStat)
	if err != nil {
		return 0, 0.0, err
	}

	var (
		currentStat = stat.CPUStatAll
		prevTotal   = (previousStat.Idle + previousStat.IOWait + previousStat.User +
			previousStat.Nice + previousStat.System + previousStat.IRQ +
			previousStat.SoftIRQ + previousStat.Steal)
		currentTotal = (currentStat.Idle + currentStat.IOWait + currentStat.User +
			currentStat.Nice + currentStat.System + currentStat.IRQ +
			currentStat.SoftIRQ + currentStat.Steal)
	)
	previousStat = currentStat
	return currentTotal - prevTotal, float64(len(stat.CPUStats)) * 100., nil
}
<|endoftext|>


<commit_before>package main

// basicEditor represents a basic editor.
// Valid positions are in range [0, len(e.buf)].
type basicEditor struct {
	pos int
	buf []rune
}

// move moves the position to the given position.
// Given a invalid position, move sets the position at the end of the buffer.
func (e *basicEditor) move(to int) {
	switch {
	case to >= len(e.buf):
		e.pos = len(e.buf)
	case to <= 0:
		e.pos = 0
	default:
		e.pos = to
	}
}

// insert inserts s into the buffer at the given position.
// Given a invalid position, insert considers the position to be at the end of the buffer.
func (e *basicEditor) insert(s []rune, at int) {
	switch {
	case at < 0:
		at = 0
	case at > len(e.buf):
		at = len(e.buf)
	}
	switch at {
	case 0:
		e.buf = append(s, e.buf...)
	case len(e.buf):
		e.buf = append(e.buf, s...)
	default:
		s = append(e.buf[:at], s...)
		e.buf = append(s, e.buf[at:]...)
	}
	if at <= e.pos {
		e.pos += len(s)
	}
}

func max(m, n int) int {
	if m > n {
		return m
	}
	return n
}

func min(m, n int) int {
	if m < n {
		return m
	}
	return n
}

func constrain(n, low, high int) int {
	if n < low {
		return low
	}
	if n > high {
		return high
	}
	return n
}

// delete deletes runes from the buffer [from, to].
// Given a invalid position, delete considers the position to be at the end of the buffer.
func (e *basicEditor) delete(from, to int) {
	left := constrain(min(from, to), 0, len(e.buf))
	right := constrain(max(from, to), 0, len(e.buf))
	switch {
	case left == 0:
		e.buf = e.buf[right:]
	case right == len(e.buf):
		e.buf = e.buf[:left]
	default:
		e.buf = append(e.buf[:left], e.buf[right:]...)
	}
	switch {
	case e.pos < left:
	case right < e.pos:
		e.pos = e.pos - (right - left)
	default:
		e.pos = left
	}
}

// slice slices the buffer [from, to].
// Given a invalid position, slice considers the position to be at the end of the buffer.
func (e *basicEditor) slice(from, to int) []rune {
	left := constrain(min(from, to), 0, len(e.buf))
	right := constrain(max(from, to), 0, len(e.buf))
	return e.buf[left:right]
}
<commit_msg>Fix a bug which makes odd behavior of e.insert<commit_after>package main

// basicEditor represents a basic editor.
// Valid positions are in range [0, len(e.buf)].
type basicEditor struct {
	pos int
	buf []rune
}

// move moves the position to the given position.
// Given a invalid position, move sets the position at the end of the buffer.
func (e *basicEditor) move(to int) {
	switch {
	case to >= len(e.buf):
		e.pos = len(e.buf)
	case to <= 0:
		e.pos = 0
	default:
		e.pos = to
	}
}

// insert inserts s into the buffer at the given position.
// Given a invalid position, insert considers the position to be at the end of the buffer.
func (e *basicEditor) insert(s []rune, at int) {
	switch {
	case at < 0:
		at = 0
	case at > len(e.buf):
		at = len(e.buf)
	}
	switch at {
	case 0:
		e.buf = append(s, e.buf...)
	case len(e.buf):
		e.buf = append(e.buf, s...)
	default:
		s = append(e.buf[:at:at], s...)
		e.buf = append(s, e.buf[at:]...)
	}
	if at <= e.pos {
		e.pos += len(s)
	}
}

func max(m, n int) int {
	if m > n {
		return m
	}
	return n
}

func min(m, n int) int {
	if m < n {
		return m
	}
	return n
}

func constrain(n, low, high int) int {
	if n < low {
		return low
	}
	if n > high {
		return high
	}
	return n
}

// delete deletes runes from the buffer [from, to].
// Given a invalid position, delete considers the position to be at the end of the buffer.
func (e *basicEditor) delete(from, to int) {
	left := constrain(min(from, to), 0, len(e.buf))
	right := constrain(max(from, to), 0, len(e.buf))
	switch {
	case left == 0:
		e.buf = e.buf[right:]
	case right == len(e.buf):
		e.buf = e.buf[:left]
	default:
		e.buf = append(e.buf[:left], e.buf[right:]...)
	}
	switch {
	case e.pos < left:
	case right < e.pos:
		e.pos = e.pos - (right - left)
	default:
		e.pos = left
	}
}

// slice slices the buffer [from, to].
// Given a invalid position, slice considers the position to be at the end of the buffer.
func (e *basicEditor) slice(from, to int) []rune {
	left := constrain(min(from, to), 0, len(e.buf))
	right := constrain(max(from, to), 0, len(e.buf))
	return e.buf[left:right]
}
<|endoftext|>


<commit_before>package batchposter

import (
	"errors"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"
)

var (
	ErrBufferFull = errors.New("buffer full")
)

type BatchPoster struct {
	url        string        // the url to POST to when flushing the buffer
	buffersize int           // the maximum amount of posts that can be batched
	autoflush  time.Duration // max time a buffer can fillup before flushing
	log        *log.Logger   // where errors get reported to

	mu     sync.RWMutex
	buffer []string
	idx    int
}

func New(url string, maxbatch int, maxtime time.Duration, l *log.Logger) *BatchPoster {

	obj := &BatchPoster{url: url, buffersize: maxbatch, autoflush: maxtime, log: l}
	obj.idx = 0
	obj.buffer = make([]string, obj.buffersize)

	go func() {
		for {
			// TODO: Add ability to start/stop autoflushing
			time.Sleep(obj.autoflush)
			obj.flush()
		}
	}()

	return obj
}

func (b *BatchPoster) Post(payload string) error {

	if b.full() {

		// something is wrong, buffer should never be full. Try flushing and ignore errors.
		go b.flush()

		b.log.Println(ErrBufferFull)
		return ErrBufferFull
	}

	err := b.add(payload)
	if err != nil {
		return err
	}

	if b.full() {
		err := b.flush()
		if err != nil {
			return err
		}
	}

	return nil
}

//////////////////////////////////////////////////////////////////////////
// private parts
//////////////////////////////////////////////////////////////////////////

func (b *BatchPoster) full() bool {

	b.mu.RLock()
	defer b.mu.RUnlock()

	return b.idx >= b.buffersize
}

func (b *BatchPoster) add(payload string) error {

	b.mu.Lock()
	defer b.mu.Unlock()

	// add to buffer
	b.buffer[b.idx] = payload
	b.idx++

	return nil
}

func (b *BatchPoster) flush() error {

	b.mu.Lock()
	defer b.mu.Unlock()

	// bail on nothing to post
	if b.idx == 0 {
		return nil
	}

	// post batch
	batch := strings.Join(b.buffer, "\n")
	_, err := http.Post(b.url, "", strings.NewReader(batch))
	if err != nil {
		b.log.Println(err)
		return err
	}

	// reset
	for i := 0; i < b.buffersize; i++ {
		b.buffer[i] = ""
	}
	b.idx = 0

	return nil
}
<commit_msg>reduce stuttering<commit_after>package batchposter

import (
	"errors"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"
)

var (
	ErrBufferFull = errors.New("buffer full")
)

type B struct {
	url        string        // the url to POST to when flushing the buffer
	buffersize int           // the maximum amount of posts that can be batched
	autoflush  time.Duration // max time a buffer can fillup before flushing
	log        *log.Logger   // where errors get reported to

	mu     sync.RWMutex
	buffer []string
	idx    int
}

func New(url string, maxbatch int, maxtime time.Duration, l *log.Logger) *B {

	obj := &B{url: url, buffersize: maxbatch, autoflush: maxtime, log: l}
	obj.idx = 0
	obj.buffer = make([]string, obj.buffersize)

	go func() {
		for {
			// TODO: Add ability to start/stop autoflushing
			time.Sleep(obj.autoflush)
			obj.flush()
		}
	}()

	return obj
}

func (b *B) Post(payload string) error {

	if b.full() {

		// something is wrong, buffer should never be full. Try flushing and ignore errors.
		go b.flush()

		b.log.Println(ErrBufferFull)
		return ErrBufferFull
	}

	err := b.add(payload)
	if err != nil {
		return err
	}

	if b.full() {
		err := b.flush()
		if err != nil {
			return err
		}
	}

	return nil
}

//////////////////////////////////////////////////////////////////////////
// private parts
//////////////////////////////////////////////////////////////////////////

func (b *B) full() bool {

	b.mu.RLock()
	defer b.mu.RUnlock()

	return b.idx >= b.buffersize
}

func (b *B) add(payload string) error {

	b.mu.Lock()
	defer b.mu.Unlock()

	// add to buffer
	b.buffer[b.idx] = payload
	b.idx++

	return nil
}

func (b *B) flush() error {

	b.mu.Lock()
	defer b.mu.Unlock()

	// bail on nothing to post
	if b.idx == 0 {
		return nil
	}

	// post batch
	batch := strings.Join(b.buffer, "\n")
	_, err := http.Post(b.url, "", strings.NewReader(batch))
	if err != nil {
		b.log.Println(err)
		return err
	}

	// reset
	for i := 0; i < b.buffersize; i++ {
		b.buffer[i] = ""
	}
	b.idx = 0

	return nil
}
<|endoftext|>