<commit_before>/*
 * Minio Cloud Storage, (C) 2016 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cmd

import (
	"io"
	"os"
	pathutil "path"
	"runtime"
)

// Removes only the file at given path does not remove
// any parent directories, handles long paths for
// windows automatically.
func fsRemoveFile(filePath string) (err error) {
	if filePath == "" {
		return traceError(errInvalidArgument)
	}

	if err = checkPathLength(filePath); err != nil {
		return traceError(err)
	}

	if err = os.Remove(preparePath(filePath)); err != nil {
		if os.IsNotExist(err) {
			return traceError(errFileNotFound)
		} else if os.IsPermission(err) {
			return traceError(errFileAccessDenied)
		}
		return traceError(err)
	}

	return nil
}

// Removes all files and folders at a given path, handles
// long paths for windows automatically.
func fsRemoveAll(dirPath string) (err error) {
	if dirPath == "" {
		return traceError(errInvalidArgument)
	}

	if err = checkPathLength(dirPath); err != nil {
		return traceError(err)
	}

	if err = removeAll(dirPath); err != nil {
		if os.IsPermission(err) {
			return traceError(errVolumeAccessDenied)
		}
		return traceError(err)
	}

	return nil
}

// Removes a directory only if its empty, handles long
// paths for windows automatically.
func fsRemoveDir(dirPath string) (err error) {
	if dirPath == "" {
		return traceError(errInvalidArgument)
	}

	if err = checkPathLength(dirPath); err != nil {
		return traceError(err)
	}

	if err = os.Remove(preparePath(dirPath)); err != nil {
		if os.IsNotExist(err) {
			return traceError(errVolumeNotFound)
		} else if isSysErrNotEmpty(err) {
			return traceError(errVolumeNotEmpty)
		}
		return traceError(err)
	}

	return nil
}

// Creates a new directory, parent dir should exist
// otherwise returns an error. If directory already
// exists returns an error. Windows long paths
// are handled automatically.
func fsMkdir(dirPath string) (err error) {
	if dirPath == "" {
		return traceError(errInvalidArgument)
	}

	if err = checkPathLength(dirPath); err != nil {
		return traceError(err)
	}

	if err = os.Mkdir(preparePath(dirPath), 0777); err != nil {
		if os.IsExist(err) {
			return traceError(errVolumeExists)
		} else if os.IsPermission(err) {
			return traceError(errDiskAccessDenied)
		} else if isSysErrNotDir(err) {
			// File path cannot be verified since
			// one of the parents is a file.
			return traceError(errDiskAccessDenied)
		} else if isSysErrPathNotFound(err) {
			// Add specific case for windows.
			return traceError(errDiskAccessDenied)
		}
		return traceError(err)
	}

	return nil
}

func fsStat(statLoc string) (os.FileInfo, error) {
	if statLoc == "" {
		return nil, traceError(errInvalidArgument)
	}
	if err := checkPathLength(statLoc); err != nil {
		return nil, traceError(err)
	}
	fi, err := osStat(preparePath(statLoc))
	if err != nil {
		return nil, traceError(err)
	}

	return fi, nil
}

// Lookup if directory exists, returns directory
// attributes upon success.
func fsStatDir(statDir string) (os.FileInfo, error) {
	fi, err := fsStat(statDir)
	if err != nil {
		err = errorCause(err)
		if os.IsNotExist(err) {
			return nil, traceError(errVolumeNotFound)
		} else if os.IsPermission(err) {
			return nil, traceError(errVolumeAccessDenied)
		}
		return nil, traceError(err)
	}

	if !fi.IsDir() {
		return nil, traceError(errVolumeAccessDenied)
	}

	return fi, nil
}

// Lookup if file exists, returns file attributes upon success
func fsStatFile(statFile string) (os.FileInfo, error) {
	fi, err := fsStat(statFile)
	if err != nil {
		err = errorCause(err)
		if os.IsNotExist(err) {
			return nil, traceError(errFileNotFound)
		} else if os.IsPermission(err) {
			return nil, traceError(errFileAccessDenied)
		} else if isSysErrNotDir(err) {
			return nil, traceError(errFileAccessDenied)
		} else if isSysErrPathNotFound(err) {
			return nil, traceError(errFileNotFound)
		}
		return nil, traceError(err)
	}
	if fi.IsDir() {
		return nil, traceError(errFileAccessDenied)
	}
	return fi, nil
}

// Opens the file at given path, optionally from an offset. Upon success returns
// a readable stream and the size of the readable stream.
func fsOpenFile(readPath string, offset int64) (io.ReadCloser, int64, error) {
	if readPath == "" || offset < 0 {
		return nil, 0, traceError(errInvalidArgument)
	}
	if err := checkPathLength(readPath); err != nil {
		return nil, 0, traceError(err)
	}

	fr, err := os.Open(preparePath(readPath))
	if err != nil {
		if os.IsNotExist(err) {
			return nil, 0, traceError(errFileNotFound)
		} else if os.IsPermission(err) {
			return nil, 0, traceError(errFileAccessDenied)
		} else if isSysErrNotDir(err) {
			// File path cannot be verified since one of the parents is a file.
			return nil, 0, traceError(errFileAccessDenied)
		} else if isSysErrPathNotFound(err) {
			// Add specific case for windows.
			return nil, 0, traceError(errFileNotFound)
		}
		return nil, 0, traceError(err)
	}

	// Stat to get the size of the file at path.
	st, err := osStat(preparePath(readPath))
	if err != nil {
		return nil, 0, traceError(err)
	}

	// Verify if its not a regular file, since subsequent Seek is undefined.
	if !st.Mode().IsRegular() {
		return nil, 0, traceError(errIsNotRegular)
	}

	// Seek to the requested offset.
	if offset > 0 {
		_, err = fr.Seek(offset, os.SEEK_SET)
		if err != nil {
			return nil, 0, traceError(err)
		}
	}

	// Success.
	return fr, st.Size(), nil
}

// Creates a file and copies data from incoming reader. Staging buffer is used by io.CopyBuffer.
func fsCreateFile(filePath string, reader io.Reader, buf []byte, fallocSize int64) (int64, error) {
	if filePath == "" || reader == nil {
		return 0, traceError(errInvalidArgument)
	}

	if err := checkPathLength(filePath); err != nil {
		return 0, traceError(err)
	}

	if err := mkdirAll(pathutil.Dir(filePath), 0777); err != nil {
		return 0, traceError(err)
	}

	if err := checkDiskFree(pathutil.Dir(filePath), fallocSize); err != nil {
		return 0, traceError(err)
	}

	writer, err := os.OpenFile(preparePath(filePath), os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
		// File path cannot be verified since one of the parents is a file.
		if isSysErrNotDir(err) {
			return 0, traceError(errFileAccessDenied)
		}
		return 0, err
	}
	defer writer.Close()

	// Fallocate only if the size is final object is known.
	if fallocSize > 0 {
		if err = fsFAllocate(int(writer.Fd()), 0, fallocSize); err != nil {
			return 0, traceError(err)
		}
	}

	var bytesWritten int64
	if buf != nil {
		bytesWritten, err = io.CopyBuffer(writer, reader, buf)
		if err != nil {
			return 0, traceError(err)
		}
	} else {
		bytesWritten, err = io.Copy(writer, reader)
		if err != nil {
			return 0, traceError(err)
		}
	}
	return bytesWritten, nil
}

// Removes uploadID at destination path.
func fsRemoveUploadIDPath(basePath, uploadIDPath string) error {
	if basePath == "" || uploadIDPath == "" {
		return traceError(errInvalidArgument)
	}
	if err := checkPathLength(basePath); err != nil {
		return traceError(err)
	}
	if err := checkPathLength(uploadIDPath); err != nil {
		return traceError(err)
	}

	// List all the entries in uploadID.
	entries, err := readDir(uploadIDPath)
	if err != nil && err != errFileNotFound {
		return traceError(err)
	}

	// Delete all the entries obtained from previous readdir.
	for _, entryPath := range entries {
		err = fsDeleteFile(basePath, pathJoin(uploadIDPath, entryPath))
		if err != nil && err != errFileNotFound {
			return traceError(err)
		}
	}

	return nil
}

// fsFAllocate is similar to Fallocate but provides a convenient
// wrapper to handle various operating system specific errors.
func fsFAllocate(fd int, offset int64, len int64) (err error) {
	e := Fallocate(fd, offset, len)
	// Ignore errors when Fallocate is not supported in the current system
	if e != nil && !isSysErrNoSys(e) && !isSysErrOpNotSupported(e) {
		switch {
		case isSysErrNoSpace(e):
			err = errDiskFull
		case isSysErrIO(e):
			err = e
		default:
			// For errors: EBADF, EINTR, EINVAL, ENODEV, EPERM, ESPIPE  and ETXTBSY
			// Appending was failed anyway, returns unexpected error
			err = errUnexpected
		}
		return err
	}

	return nil
}

// Renames source path to destination path, creates all the
// missing parents if they don't exist.
func fsRenameFile(sourcePath, destPath string) error {
	if err := checkPathLength(sourcePath); err != nil {
		return traceError(err)
	}
	if err := checkPathLength(destPath); err != nil {
		return traceError(err)
	}
	// Verify if source path exists.
	if _, err := os.Stat(preparePath(sourcePath)); err != nil {
		if os.IsNotExist(err) {
			return traceError(errFileNotFound)
		} else if os.IsPermission(err) {
			return traceError(errFileAccessDenied)
		} else if isSysErrPathNotFound(err) {
			return traceError(errFileNotFound)
		} else if isSysErrNotDir(err) {
			// File path cannot be verified since one of the parents is a file.
			return traceError(errFileAccessDenied)
		}
		return traceError(err)
	}
	if err := mkdirAll(pathutil.Dir(destPath), 0777); err != nil {
		return traceError(err)
	}
	if err := os.Rename(preparePath(sourcePath), preparePath(destPath)); err != nil {
		return traceError(err)
	}
	return nil
}

// fsDeleteFile is a wrapper for deleteFile(), after checking the path length.
func fsDeleteFile(basePath, deletePath string) error {
	if err := checkPathLength(basePath); err != nil {
		return traceError(err)
	}

	if err := checkPathLength(deletePath); err != nil {
		return traceError(err)
	}

	return deleteFile(basePath, deletePath)
}

// fsRemoveMeta safely removes a locked file and takes care of Windows special case
func fsRemoveMeta(basePath, deletePath, tmpDir string) error {
	// Special case for windows please read through.
	if runtime.GOOS == globalWindowsOSName {
		// Ordinarily windows does not permit deletion or renaming of files still
		// in use, but if all open handles to that file were opened with FILE_SHARE_DELETE
		// then it can permit renames and deletions of open files.
		//
		// There are however some gotchas with this, and it is worth listing them here.
		// Firstly, Windows never allows you to really delete an open file, rather it is
		// flagged as delete pending and its entry in its directory remains visible
		// (though no new file handles may be opened to it) and when the very last
		// open handle to the file in the system is closed, only then is it truly
		// deleted. Well, actually only sort of truly deleted, because Windows only
		// appears to remove the file entry from the directory, but in fact that
		// entry is merely hidden and actually still exists and attempting to create
		// a file with the same name will return an access denied error. How long it
		// silently exists for depends on a range of factors, but put it this way:
		// if your code loops creating and deleting the same file name as you might
		// when operating a lock file, you're going to see lots of random spurious
		// access denied errors and truly dismal lock file performance compared to POSIX.
		//
		// We work-around these un-POSIX file semantics by taking a dual step to
		// deleting files. Firstly, it renames the file to tmp location into multipartTmpBucket
		// We always open files with FILE_SHARE_DELETE permission enabled, with that
		// flag Windows permits renaming and deletion, and because the name was changed
		// to a very random name somewhere not in its origin directory before deletion,
		// you don't see those unexpected random errors when creating files with the
		// same name as a recently deleted file as you do anywhere else on Windows.
		// Because the file is probably not in its original containing directory any more,
		// deletions of that directory will not fail with "directory not empty" as they
		// otherwise normally would either.

		tmpPath := pathJoin(tmpDir, mustGetUUID())

		fsRenameFile(deletePath, tmpPath)

		// Proceed to deleting the directory if empty
		fsDeleteFile(basePath, pathutil.Dir(deletePath))

		// Finally delete the renamed file.
		return fsDeleteFile(tmpDir, tmpPath)
	}
	return fsDeleteFile(basePath, deletePath)
}
<commit_msg>fs: Return errVolumeNotEmpty properly if path not empty. (#4794)<commit_after>/*
 * Minio Cloud Storage, (C) 2016 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cmd

import (
	"io"
	"os"
	pathutil "path"
	"runtime"
)

// Removes only the file at given path does not remove
// any parent directories, handles long paths for
// windows automatically.
func fsRemoveFile(filePath string) (err error) {
	if filePath == "" {
		return traceError(errInvalidArgument)
	}

	if err = checkPathLength(filePath); err != nil {
		return traceError(err)
	}

	if err = os.Remove(preparePath(filePath)); err != nil {
		if os.IsNotExist(err) {
			return traceError(errFileNotFound)
		} else if os.IsPermission(err) {
			return traceError(errFileAccessDenied)
		}
		return traceError(err)
	}

	return nil
}

// Removes all files and folders at a given path, handles
// long paths for windows automatically.
func fsRemoveAll(dirPath string) (err error) {
	if dirPath == "" {
		return traceError(errInvalidArgument)
	}

	if err = checkPathLength(dirPath); err != nil {
		return traceError(err)
	}

	if err = removeAll(dirPath); err != nil {
		if os.IsPermission(err) {
			return traceError(errVolumeAccessDenied)
		} else if isSysErrNotEmpty(err) {
			return traceError(errVolumeNotEmpty)
		}
		return traceError(err)
	}

	return nil
}

// Removes a directory only if its empty, handles long
// paths for windows automatically.
func fsRemoveDir(dirPath string) (err error) {
	if dirPath == "" {
		return traceError(errInvalidArgument)
	}

	if err = checkPathLength(dirPath); err != nil {
		return traceError(err)
	}

	if err = os.Remove(preparePath(dirPath)); err != nil {
		if os.IsNotExist(err) {
			return traceError(errVolumeNotFound)
		} else if isSysErrNotEmpty(err) {
			return traceError(errVolumeNotEmpty)
		}
		return traceError(err)
	}

	return nil
}

// Creates a new directory, parent dir should exist
// otherwise returns an error. If directory already
// exists returns an error. Windows long paths
// are handled automatically.
func fsMkdir(dirPath string) (err error) {
	if dirPath == "" {
		return traceError(errInvalidArgument)
	}

	if err = checkPathLength(dirPath); err != nil {
		return traceError(err)
	}

	if err = os.Mkdir(preparePath(dirPath), 0777); err != nil {
		if os.IsExist(err) {
			return traceError(errVolumeExists)
		} else if os.IsPermission(err) {
			return traceError(errDiskAccessDenied)
		} else if isSysErrNotDir(err) {
			// File path cannot be verified since
			// one of the parents is a file.
			return traceError(errDiskAccessDenied)
		} else if isSysErrPathNotFound(err) {
			// Add specific case for windows.
			return traceError(errDiskAccessDenied)
		}
		return traceError(err)
	}

	return nil
}

func fsStat(statLoc string) (os.FileInfo, error) {
	if statLoc == "" {
		return nil, traceError(errInvalidArgument)
	}
	if err := checkPathLength(statLoc); err != nil {
		return nil, traceError(err)
	}
	fi, err := osStat(preparePath(statLoc))
	if err != nil {
		return nil, traceError(err)
	}

	return fi, nil
}

// Lookup if directory exists, returns directory
// attributes upon success.
func fsStatDir(statDir string) (os.FileInfo, error) {
	fi, err := fsStat(statDir)
	if err != nil {
		err = errorCause(err)
		if os.IsNotExist(err) {
			return nil, traceError(errVolumeNotFound)
		} else if os.IsPermission(err) {
			return nil, traceError(errVolumeAccessDenied)
		}
		return nil, traceError(err)
	}

	if !fi.IsDir() {
		return nil, traceError(errVolumeAccessDenied)
	}

	return fi, nil
}

// Lookup if file exists, returns file attributes upon success
func fsStatFile(statFile string) (os.FileInfo, error) {
	fi, err := fsStat(statFile)
	if err != nil {
		err = errorCause(err)
		if os.IsNotExist(err) {
			return nil, traceError(errFileNotFound)
		} else if os.IsPermission(err) {
			return nil, traceError(errFileAccessDenied)
		} else if isSysErrNotDir(err) {
			return nil, traceError(errFileAccessDenied)
		} else if isSysErrPathNotFound(err) {
			return nil, traceError(errFileNotFound)
		}
		return nil, traceError(err)
	}
	if fi.IsDir() {
		return nil, traceError(errFileAccessDenied)
	}
	return fi, nil
}

// Opens the file at given path, optionally from an offset. Upon success returns
// a readable stream and the size of the readable stream.
func fsOpenFile(readPath string, offset int64) (io.ReadCloser, int64, error) {
	if readPath == "" || offset < 0 {
		return nil, 0, traceError(errInvalidArgument)
	}
	if err := checkPathLength(readPath); err != nil {
		return nil, 0, traceError(err)
	}

	fr, err := os.Open(preparePath(readPath))
	if err != nil {
		if os.IsNotExist(err) {
			return nil, 0, traceError(errFileNotFound)
		} else if os.IsPermission(err) {
			return nil, 0, traceError(errFileAccessDenied)
		} else if isSysErrNotDir(err) {
			// File path cannot be verified since one of the parents is a file.
			return nil, 0, traceError(errFileAccessDenied)
		} else if isSysErrPathNotFound(err) {
			// Add specific case for windows.
			return nil, 0, traceError(errFileNotFound)
		}
		return nil, 0, traceError(err)
	}

	// Stat to get the size of the file at path.
	st, err := osStat(preparePath(readPath))
	if err != nil {
		return nil, 0, traceError(err)
	}

	// Verify if its not a regular file, since subsequent Seek is undefined.
	if !st.Mode().IsRegular() {
		return nil, 0, traceError(errIsNotRegular)
	}

	// Seek to the requested offset.
	if offset > 0 {
		_, err = fr.Seek(offset, os.SEEK_SET)
		if err != nil {
			return nil, 0, traceError(err)
		}
	}

	// Success.
	return fr, st.Size(), nil
}

// Creates a file and copies data from incoming reader. Staging buffer is used by io.CopyBuffer.
func fsCreateFile(filePath string, reader io.Reader, buf []byte, fallocSize int64) (int64, error) {
	if filePath == "" || reader == nil {
		return 0, traceError(errInvalidArgument)
	}

	if err := checkPathLength(filePath); err != nil {
		return 0, traceError(err)
	}

	if err := mkdirAll(pathutil.Dir(filePath), 0777); err != nil {
		return 0, traceError(err)
	}

	if err := checkDiskFree(pathutil.Dir(filePath), fallocSize); err != nil {
		return 0, traceError(err)
	}

	writer, err := os.OpenFile(preparePath(filePath), os.O_CREATE|os.O_WRONLY, 0666)
	if err != nil {
		// File path cannot be verified since one of the parents is a file.
		if isSysErrNotDir(err) {
			return 0, traceError(errFileAccessDenied)
		}
		return 0, err
	}
	defer writer.Close()

	// Fallocate only if the size is final object is known.
	if fallocSize > 0 {
		if err = fsFAllocate(int(writer.Fd()), 0, fallocSize); err != nil {
			return 0, traceError(err)
		}
	}

	var bytesWritten int64
	if buf != nil {
		bytesWritten, err = io.CopyBuffer(writer, reader, buf)
		if err != nil {
			return 0, traceError(err)
		}
	} else {
		bytesWritten, err = io.Copy(writer, reader)
		if err != nil {
			return 0, traceError(err)
		}
	}
	return bytesWritten, nil
}

// Removes uploadID at destination path.
func fsRemoveUploadIDPath(basePath, uploadIDPath string) error {
	if basePath == "" || uploadIDPath == "" {
		return traceError(errInvalidArgument)
	}
	if err := checkPathLength(basePath); err != nil {
		return traceError(err)
	}
	if err := checkPathLength(uploadIDPath); err != nil {
		return traceError(err)
	}

	// List all the entries in uploadID.
	entries, err := readDir(uploadIDPath)
	if err != nil && err != errFileNotFound {
		return traceError(err)
	}

	// Delete all the entries obtained from previous readdir.
	for _, entryPath := range entries {
		err = fsDeleteFile(basePath, pathJoin(uploadIDPath, entryPath))
		if err != nil && err != errFileNotFound {
			return traceError(err)
		}
	}

	return nil
}

// fsFAllocate is similar to Fallocate but provides a convenient
// wrapper to handle various operating system specific errors.
func fsFAllocate(fd int, offset int64, len int64) (err error) {
	e := Fallocate(fd, offset, len)
	// Ignore errors when Fallocate is not supported in the current system
	if e != nil && !isSysErrNoSys(e) && !isSysErrOpNotSupported(e) {
		switch {
		case isSysErrNoSpace(e):
			err = errDiskFull
		case isSysErrIO(e):
			err = e
		default:
			// For errors: EBADF, EINTR, EINVAL, ENODEV, EPERM, ESPIPE  and ETXTBSY
			// Appending was failed anyway, returns unexpected error
			err = errUnexpected
		}
		return err
	}

	return nil
}

// Renames source path to destination path, creates all the
// missing parents if they don't exist.
func fsRenameFile(sourcePath, destPath string) error {
	if err := checkPathLength(sourcePath); err != nil {
		return traceError(err)
	}
	if err := checkPathLength(destPath); err != nil {
		return traceError(err)
	}
	// Verify if source path exists.
	if _, err := os.Stat(preparePath(sourcePath)); err != nil {
		if os.IsNotExist(err) {
			return traceError(errFileNotFound)
		} else if os.IsPermission(err) {
			return traceError(errFileAccessDenied)
		} else if isSysErrPathNotFound(err) {
			return traceError(errFileNotFound)
		} else if isSysErrNotDir(err) {
			// File path cannot be verified since one of the parents is a file.
			return traceError(errFileAccessDenied)
		}
		return traceError(err)
	}
	if err := mkdirAll(pathutil.Dir(destPath), 0777); err != nil {
		return traceError(err)
	}
	if err := os.Rename(preparePath(sourcePath), preparePath(destPath)); err != nil {
		return traceError(err)
	}
	return nil
}

// fsDeleteFile is a wrapper for deleteFile(), after checking the path length.
func fsDeleteFile(basePath, deletePath string) error {
	if err := checkPathLength(basePath); err != nil {
		return traceError(err)
	}

	if err := checkPathLength(deletePath); err != nil {
		return traceError(err)
	}

	return deleteFile(basePath, deletePath)
}

// fsRemoveMeta safely removes a locked file and takes care of Windows special case
func fsRemoveMeta(basePath, deletePath, tmpDir string) error {
	// Special case for windows please read through.
	if runtime.GOOS == globalWindowsOSName {
		// Ordinarily windows does not permit deletion or renaming of files still
		// in use, but if all open handles to that file were opened with FILE_SHARE_DELETE
		// then it can permit renames and deletions of open files.
		//
		// There are however some gotchas with this, and it is worth listing them here.
		// Firstly, Windows never allows you to really delete an open file, rather it is
		// flagged as delete pending and its entry in its directory remains visible
		// (though no new file handles may be opened to it) and when the very last
		// open handle to the file in the system is closed, only then is it truly
		// deleted. Well, actually only sort of truly deleted, because Windows only
		// appears to remove the file entry from the directory, but in fact that
		// entry is merely hidden and actually still exists and attempting to create
		// a file with the same name will return an access denied error. How long it
		// silently exists for depends on a range of factors, but put it this way:
		// if your code loops creating and deleting the same file name as you might
		// when operating a lock file, you're going to see lots of random spurious
		// access denied errors and truly dismal lock file performance compared to POSIX.
		//
		// We work-around these un-POSIX file semantics by taking a dual step to
		// deleting files. Firstly, it renames the file to tmp location into multipartTmpBucket
		// We always open files with FILE_SHARE_DELETE permission enabled, with that
		// flag Windows permits renaming and deletion, and because the name was changed
		// to a very random name somewhere not in its origin directory before deletion,
		// you don't see those unexpected random errors when creating files with the
		// same name as a recently deleted file as you do anywhere else on Windows.
		// Because the file is probably not in its original containing directory any more,
		// deletions of that directory will not fail with "directory not empty" as they
		// otherwise normally would either.

		tmpPath := pathJoin(tmpDir, mustGetUUID())

		fsRenameFile(deletePath, tmpPath)

		// Proceed to deleting the directory if empty
		fsDeleteFile(basePath, pathutil.Dir(deletePath))

		// Finally delete the renamed file.
		return fsDeleteFile(tmpDir, tmpPath)
	}
	return fsDeleteFile(basePath, deletePath)
}
<|endoftext|>


<commit_before>package metadata

import (
	"fmt"
	"reflect"
	"strconv"
)

// TODO: rename to SchemaMan Type?
type DatamanType string

// DatamanType is a method for describing the golang type in schema
// This allows us to treat everything as interfaces{} in most of the code yet
// still be in a strongly typed language

const (
	Document DatamanType = "document"
	String               = "string" // max len 4096
	Text                 = "text"
	// We should support converting anything to an int that doesn't lose data
	Int = "int"
	// TODO: int64
	// TODO: uint
	// TODO: uint64
	Bool = "bool"
	// TODO: actually implement
	DateTime = "datetime"
)

// TODO: have this register the type? Right now this assumes this is in-sync with field_type_internal.go (which is bad to do)
func (f DatamanType) ToFieldType() *FieldType {
	return &FieldType{
		Name:        "_" + string(f),
		DatamanType: f,
	}
}

// Normalize the given interface into what we want/expect
func (f DatamanType) Normalize(val interface{}) (interface{}, error) {
	switch f {
	case Document:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case map[string]interface{}:
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a document")
		}

	case String:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case string:
			// TODO: default, code this out somewhere
			if len(typedVal) > 4096 {
				return nil, fmt.Errorf("String too long!")
			}
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a string")
		}

	case Text:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case string:
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a string")
		}
		s, ok := val.(string)
		if !ok {
			return nil, fmt.Errorf("Not text")
		}
		return s, nil
	case Int:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		// TODO: remove? Or error if we would lose precision
		case int32:
			return int(typedVal), nil
		case int64:
			return int(typedVal), nil
		case int:
			return typedVal, nil
		case float64:
			return int(typedVal), nil
		case string:
			return strconv.ParseInt(typedVal, 10, 64)
		default:
			return nil, fmt.Errorf("Unknown Int type: %s", reflect.TypeOf(val))
		}
	case Bool:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case bool:
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a bool")
		}
	// TODO: implement
	case DateTime:
		return nil, fmt.Errorf("DateTime currently unimplemented")
	}
	return nil, fmt.Errorf("Unknown type \"%s\" defined", f)
}

// TODO: have method which will reflect type to determine dataman type
// then we can have the datasources just call the method with the largest thing
// they can store in a given field type to determine the closest dataman_type
<commit_msg>Support string representation of bool<commit_after>package metadata

import (
	"fmt"
	"reflect"
	"strconv"
)

// TODO: rename to SchemaMan Type?
type DatamanType string

// DatamanType is a method for describing the golang type in schema
// This allows us to treat everything as interfaces{} in most of the code yet
// still be in a strongly typed language

const (
	Document DatamanType = "document"
	String               = "string" // max len 4096
	Text                 = "text"
	// We should support converting anything to an int that doesn't lose data
	Int = "int"
	// TODO: int64
	// TODO: uint
	// TODO: uint64
	Bool = "bool"
	// TODO: actually implement
	DateTime = "datetime"
)

// TODO: have this register the type? Right now this assumes this is in-sync with field_type_internal.go (which is bad to do)
func (f DatamanType) ToFieldType() *FieldType {
	return &FieldType{
		Name:        "_" + string(f),
		DatamanType: f,
	}
}

// Normalize the given interface into what we want/expect
func (f DatamanType) Normalize(val interface{}) (interface{}, error) {
	switch f {
	case Document:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case map[string]interface{}:
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a document")
		}

	case String:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case string:
			// TODO: default, code this out somewhere
			if len(typedVal) > 4096 {
				return nil, fmt.Errorf("String too long!")
			}
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a string")
		}

	case Text:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case string:
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a string")
		}
		s, ok := val.(string)
		if !ok {
			return nil, fmt.Errorf("Not text")
		}
		return s, nil
	case Int:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		// TODO: remove? Or error if we would lose precision
		case int32:
			return int(typedVal), nil
		case int64:
			return int(typedVal), nil
		case int:
			return typedVal, nil
		case float64:
			return int(typedVal), nil
		case string:
			return strconv.ParseInt(typedVal, 10, 64)
		default:
			return nil, fmt.Errorf("Unknown Int type: %s", reflect.TypeOf(val))
		}
	case Bool:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case bool:
			return typedVal, nil
		case string:
			return strconv.ParseBool(typedVal)
		default:
			return nil, fmt.Errorf("Not a bool")
		}
	// TODO: implement
	case DateTime:
		return nil, fmt.Errorf("DateTime currently unimplemented")
	}
	return nil, fmt.Errorf("Unknown type \"%s\" defined", f)
}

// TODO: have method which will reflect type to determine dataman type
// then we can have the datasources just call the method with the largest thing
// they can store in a given field type to determine the closest dataman_type
<|endoftext|>


<commit_before>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strconv"
	"strings"
	"unicode/utf8"
)

type mainModel struct {
	grid     *sudoku.Grid
	Selected *sudoku.Cell
}

func main() {
	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	model := newModel()

	draw(model)

mainloop:
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc, termbox.KeyCtrlC:
				break mainloop
			case termbox.KeyArrowDown:
				model.MoveSelectionDown()
			case termbox.KeyArrowLeft:
				model.MoveSelectionLeft()
			case termbox.KeyArrowRight:
				model.MoveSelectionRight()
			case termbox.KeyArrowUp:
				model.MoveSelectionUp()
			}
			switch ev.Ch {
			case 'q':
				break mainloop
			case 'n':
				//TODO: since this is a destructive action, require a confirmation
				model.NewGrid()
			//TODO: do this in a more general way related to DIM
			case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
				//TODO: this is a seriously gross way of converting a rune to a string.
				num, err := strconv.Atoi(strings.Replace(strconv.QuoteRuneToASCII(ev.Ch), "'", "", -1))
				if err != nil {
					panic(err)
				}
				model.SetSelectedNumber(num)
			}
		}
		draw(model)
	}
}

func newModel() *mainModel {
	model := &mainModel{}
	model.EnsureSelected()
	return model
}

func (m *mainModel) EnsureSelected() {
	m.EnsureGrid()
	//Ensures that at least one cell is selected.
	if m.Selected == nil {
		m.Selected = m.grid.Cell(0, 0)
	}
}

func (m *mainModel) MoveSelectionLeft() {
	m.EnsureSelected()
	r := m.Selected.Row()
	c := m.Selected.Col()
	c--
	if c < 0 {
		c = 0
	}
	m.Selected = m.grid.Cell(r, c)
}

func (m *mainModel) MoveSelectionRight() {
	m.EnsureSelected()
	r := m.Selected.Row()
	c := m.Selected.Col()
	c++
	if c >= sudoku.DIM {
		c = sudoku.DIM - 1
	}
	m.Selected = m.grid.Cell(r, c)
}

func (m *mainModel) MoveSelectionUp() {
	m.EnsureSelected()
	r := m.Selected.Row()
	c := m.Selected.Col()
	r--
	if r < 0 {
		r = 0
	}
	m.Selected = m.grid.Cell(r, c)
}

func (m *mainModel) MoveSelectionDown() {
	m.EnsureSelected()
	r := m.Selected.Row()
	c := m.Selected.Col()
	r++
	if r >= sudoku.DIM {
		r = sudoku.DIM - 1
	}
	m.Selected = m.grid.Cell(r, c)
}

func (m *mainModel) EnsureGrid() {
	if m.grid == nil {
		m.NewGrid()
	}
}

func (m *mainModel) NewGrid() {
	m.grid = sudoku.GenerateGrid(nil)
	m.grid.LockFilledCells()
}

func (m *mainModel) SetSelectedNumber(num int) {
	m.EnsureSelected()
	m.Selected.SetNumber(num)
}

func draw(model *mainModel) {
	drawGrid(model)
	termbox.Flush()
}

func drawGrid(model *mainModel) {

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected.DiagramExtents()

	for y, line := range strings.Split(grid.Diagram(true), "\n") {
		x := 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)

			if ch == numberRune {
				defaultColor = termbox.ColorBlue
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = termbox.ColorWhite
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
	}
}
<commit_msg>Render locked cells differently<commit_after>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strconv"
	"strings"
	"unicode/utf8"
)

type mainModel struct {
	grid     *sudoku.Grid
	Selected *sudoku.Cell
}

func main() {
	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	model := newModel()

	draw(model)

mainloop:
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc, termbox.KeyCtrlC:
				break mainloop
			case termbox.KeyArrowDown:
				model.MoveSelectionDown()
			case termbox.KeyArrowLeft:
				model.MoveSelectionLeft()
			case termbox.KeyArrowRight:
				model.MoveSelectionRight()
			case termbox.KeyArrowUp:
				model.MoveSelectionUp()
			}
			switch ev.Ch {
			case 'q':
				break mainloop
			case 'n':
				//TODO: since this is a destructive action, require a confirmation
				model.NewGrid()
			//TODO: do this in a more general way related to DIM
			case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
				//TODO: this is a seriously gross way of converting a rune to a string.
				num, err := strconv.Atoi(strings.Replace(strconv.QuoteRuneToASCII(ev.Ch), "'", "", -1))
				if err != nil {
					panic(err)
				}
				model.SetSelectedNumber(num)
			}
		}
		draw(model)
	}
}

func newModel() *mainModel {
	model := &mainModel{}
	model.EnsureSelected()
	return model
}

func (m *mainModel) EnsureSelected() {
	m.EnsureGrid()
	//Ensures that at least one cell is selected.
	if m.Selected == nil {
		m.Selected = m.grid.Cell(0, 0)
	}
}

func (m *mainModel) MoveSelectionLeft() {
	m.EnsureSelected()
	r := m.Selected.Row()
	c := m.Selected.Col()
	c--
	if c < 0 {
		c = 0
	}
	m.Selected = m.grid.Cell(r, c)
}

func (m *mainModel) MoveSelectionRight() {
	m.EnsureSelected()
	r := m.Selected.Row()
	c := m.Selected.Col()
	c++
	if c >= sudoku.DIM {
		c = sudoku.DIM - 1
	}
	m.Selected = m.grid.Cell(r, c)
}

func (m *mainModel) MoveSelectionUp() {
	m.EnsureSelected()
	r := m.Selected.Row()
	c := m.Selected.Col()
	r--
	if r < 0 {
		r = 0
	}
	m.Selected = m.grid.Cell(r, c)
}

func (m *mainModel) MoveSelectionDown() {
	m.EnsureSelected()
	r := m.Selected.Row()
	c := m.Selected.Col()
	r++
	if r >= sudoku.DIM {
		r = sudoku.DIM - 1
	}
	m.Selected = m.grid.Cell(r, c)
}

func (m *mainModel) EnsureGrid() {
	if m.grid == nil {
		m.NewGrid()
	}
}

func (m *mainModel) NewGrid() {
	m.grid = sudoku.GenerateGrid(nil)
	m.grid.LockFilledCells()
}

func (m *mainModel) SetSelectedNumber(num int) {
	m.EnsureSelected()
	m.Selected.SetNumber(num)
}

func draw(model *mainModel) {
	drawGrid(model)
	termbox.Flush()
}

func drawGrid(model *mainModel) {

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected.DiagramExtents()

	for y, line := range strings.Split(grid.Diagram(true), "\n") {
		x := 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = termbox.ColorBlue
			} else if ch == lockedRune {
				defaultColor = termbox.ColorRed
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = termbox.ColorWhite
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
	}
}
<|endoftext|>


<commit_before>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strings"
	"unicode/utf8"
)

const STATUS_DEFAULT = "(→,←,↓,↑) to move cells, (0-9) to enter number, (m)ark mode, (c)ommand, (ESC) to quit"
const STATUS_MARKING = "MARKING:"
const STATUS_MARKING_POSTFIX = "   ENTER to commit, ESC to cancel"
const STATUS_COMMAND = "COMMAND: (q)uit, (n)ew puzzle, (ESC) cancel"

const GRID_INVALID = " INVALID "
const GRID_VALID = "  VALID  "
const GRID_SOLVED = "  SOLVED  "
const GRID_NOT_SOLVED = " UNSOLVED "

func main() {
	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	model := newModel()

	draw(model)

mainloop:
	for {
		evt := termbox.PollEvent()
		switch evt.Type {
		case termbox.EventKey:
			if model.state.handleInput(model, evt) {
				break mainloop
			}
		}
		draw(model)
	}
}

func clearScreen() {
	width, height := termbox.Size()
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
		}
	}
}

func draw(model *mainModel) {

	clearScreen()

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected().DiagramExtents()

	x := 0
	y := 0

	for _, line := range strings.Split(grid.Diagram(true), "\n") {
		x = 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = termbox.ColorBlue
			} else if ch == lockedRune {
				defaultColor = termbox.ColorRed
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = termbox.ColorWhite
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
		y++
	}

	x = 0
	solvedMsg := GRID_NOT_SOLVED
	fg := termbox.ColorBlue
	bg := termbox.ColorBlack
	if grid.Solved() {
		solvedMsg = GRID_SOLVED
		fg, bg = bg, fg
	}

	for _, ch := range solvedMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	//don't reset x; this next message should go to the right.
	validMsg := GRID_VALID
	fg = termbox.ColorBlue
	bg = termbox.ColorBlack
	if grid.Invalid() {
		validMsg = GRID_INVALID
		fg, bg = bg, fg
	}
	for _, ch := range validMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	y++

	x = 0
	underlined := false
	for _, ch := range model.StatusLine() {
		//The ( and ) are non-printing control characters
		if ch == '(' {
			underlined = true
			continue
		} else if ch == ')' {
			underlined = false
			continue
		}
		fg := termbox.ColorWhite
		if underlined {
			fg = fg | termbox.AttrUnderline | termbox.AttrBold
		}

		termbox.SetCell(x, y, ch, fg, termbox.ColorDefault)
		x++
	}

	termbox.Flush()
}
<commit_msg>Mark mode uses the new bold/underlined text<commit_after>/*
i-sudoku is an interactive command-line sudoku tool
*/

package main

import (
	"github.com/jkomoros/sudoku"
	"github.com/nsf/termbox-go"
	"log"
	"strings"
	"unicode/utf8"
)

const STATUS_DEFAULT = "(→,←,↓,↑) to move cells, (0-9) to enter number, (m)ark mode, (c)ommand, (ESC) to quit"
const STATUS_MARKING = "MARKING:"
const STATUS_MARKING_POSTFIX = "  (1-9) to toggle marks, (ENTER) to commit, (ESC) to cancel"
const STATUS_COMMAND = "COMMAND: (q)uit, (n)ew puzzle, (ESC) cancel"

const GRID_INVALID = " INVALID "
const GRID_VALID = "  VALID  "
const GRID_SOLVED = "  SOLVED  "
const GRID_NOT_SOLVED = " UNSOLVED "

func main() {
	if err := termbox.Init(); err != nil {
		log.Fatal("Termbox initialization failed:", err)
	}
	defer termbox.Close()

	model := newModel()

	draw(model)

mainloop:
	for {
		evt := termbox.PollEvent()
		switch evt.Type {
		case termbox.EventKey:
			if model.state.handleInput(model, evt) {
				break mainloop
			}
		}
		draw(model)
	}
}

func clearScreen() {
	width, height := termbox.Size()
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
		}
	}
}

func draw(model *mainModel) {

	clearScreen()

	grid := model.grid

	selectedTop, selectedLeft, selectedHeight, selectedWidth := model.Selected().DiagramExtents()

	x := 0
	y := 0

	for _, line := range strings.Split(grid.Diagram(true), "\n") {
		x = 0
		//The first number in range will be byte offset, but for some items like the bullet, it's two bytes.
		//But what we care about is that each item is a character.
		for _, ch := range line {

			defaultColor := termbox.ColorGreen

			numberRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_NUMBER)
			lockedRune, _ := utf8.DecodeRuneInString(sudoku.DIAGRAM_LOCKED)

			if ch == numberRune {
				defaultColor = termbox.ColorBlue
			} else if ch == lockedRune {
				defaultColor = termbox.ColorRed
			}

			backgroundColor := termbox.ColorDefault

			if x >= selectedTop && x < (selectedTop+selectedHeight) && y >= selectedLeft && y < (selectedLeft+selectedWidth) {
				//We're on the selected cell
				backgroundColor = termbox.ColorWhite
			}

			termbox.SetCell(x, y, ch, defaultColor, backgroundColor)
			x++
		}
		y++
	}

	x = 0
	solvedMsg := GRID_NOT_SOLVED
	fg := termbox.ColorBlue
	bg := termbox.ColorBlack
	if grid.Solved() {
		solvedMsg = GRID_SOLVED
		fg, bg = bg, fg
	}

	for _, ch := range solvedMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	//don't reset x; this next message should go to the right.
	validMsg := GRID_VALID
	fg = termbox.ColorBlue
	bg = termbox.ColorBlack
	if grid.Invalid() {
		validMsg = GRID_INVALID
		fg, bg = bg, fg
	}
	for _, ch := range validMsg {
		termbox.SetCell(x, y, ch, fg, bg)
		x++
	}

	y++

	x = 0
	underlined := false
	for _, ch := range model.StatusLine() {
		//The ( and ) are non-printing control characters
		if ch == '(' {
			underlined = true
			continue
		} else if ch == ')' {
			underlined = false
			continue
		}
		fg := termbox.ColorWhite
		if underlined {
			fg = fg | termbox.AttrUnderline | termbox.AttrBold
		}

		termbox.SetCell(x, y, ch, fg, termbox.ColorDefault)
		x++
	}

	termbox.Flush()
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"http"
	"junta/client"
	"junta/mon"
	"junta/paxos"
	"junta/server"
	"junta/store"
	"junta/util"
	"junta/web"
	"net"
	"os"
	"strings"
)

const (
	alpha = 50
)

// Flags
var (
	listenAddr *string = flag.String("l", "127.0.0.1:8046", "The address to bind to.")
	publishAddr *string = flag.String("L", "", "The address puslished for remote clients (default is listen address)")
	attachAddr *string = flag.String("a", "", "The address of another node to attach to.")
	webAddr *string = flag.String("w", ":8080", "Serve web requests on this address.")
	clusterName *string = flag.String("c", "local", "The non-empty cluster name.")
)

func activate(st *store.Store, self, prefix string, c *client.Client) {
	logger := util.NewLogger("activate")
	ch := make(chan store.Event)
	st.Watch("/junta/slot/*", ch)
	for ev := range ch {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			_, err := c.Set(prefix+ev.Path, self, ev.Cas)
			if err == nil {
				return
			}
			logger.Log(err)
		}
	}
}

func Usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] <cluster-name>\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\nOptions:\n")
	flag.PrintDefaults()
}

func main() {
	util.LogWriter = os.Stderr
	logger := util.NewLogger("main")

	flag.Parse()
	flag.Usage = Usage

	prefix := "/j/" + *clusterName

	if *listenAddr == "" {
		logger.Log("require a listen address")
		flag.Usage()
		os.Exit(1)
	}

	if *publishAddr == "" {
		publishAddr = listenAddr
	}

	var webListener net.Listener
	if *webAddr != "" {
		wl, err := net.Listen("tcp", *webAddr)
		if err != nil {
			panic(err)
		}
		webListener = wl
	}

	listener, err := net.Listen("tcp", *listenAddr)
	if err != nil {
		panic(err)
	}

	publishParts := strings.Split(*publishAddr, ":", 2)
	if len(publishParts) < 2 && publishParts[0] == "" {
		logger.Log("invalid publish address")
		flag.Usage()
		os.Exit(1)
	}

	outs := make(paxos.ChanPutCloserTo)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	seqn := uint64(0)
	if *attachAddr == "" { // we are the only node in a new cluster
		seqn = addPublicAddr(st, seqn + 1, self, *listenAddr)
		seqn = addHostname(st, seqn + 1, self, publishParts[0])
		seqn = addMember(st, seqn + 1, self, *listenAddr)
		seqn = claimSlot(st, seqn + 1, "1", self)
		seqn = claimLeader(st, seqn + 1, self)
		seqn = claimSlot(st, seqn + 1, "2", "")
		seqn = claimSlot(st, seqn + 1, "3", "")
		seqn = claimSlot(st, seqn + 1, "4", "")
		seqn = claimSlot(st, seqn + 1, "5", "")
		seqn = addPing(st, seqn + 1, "pong")

		cl, err = client.Dial(*listenAddr)
		if err != nil {
			panic(err)
		}
	} else {
		cl, err = client.Dial(*attachAddr)
		if err != nil {
			panic(err)
		}

		path := prefix + "/junta/info/"+ self +"/public-addr"
		_, err = cl.Set(path, *listenAddr, store.Clobber)
		if err != nil {
			panic(err)
		}

		path = prefix + "/junta/info/"+ self +"/hostname"
		_, err = cl.Set(path, os.Getenv("HOSTNAME"), store.Clobber)
		if err != nil {
			panic(err)
		}

		var snap string
		seqn, snap, err = cl.Join(self, *listenAddr)
		if err != nil {
			panic(err)
		}

		ch := make(chan store.Event)
		st.Wait(seqn + alpha, ch)
		st.Apply(1, snap)

		go func() {
			<-ch
			activate(st, self, prefix, cl)
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}
	mg := paxos.NewManager(self, seqn, alpha, st, outs)

	if *attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		for i := seqn + 1; i < seqn + alpha; i++ {
			go st.Apply(i, store.Nop)
		}
	}

	sv := &server.Server{*listenAddr, st, mg, self, prefix}

	go func() {
		panic(mon.Monitor(self, prefix, st, cl))
	}()

	go func() {
		panic(sv.Serve(listener))
	}()

	go func() {
		panic(sv.ListenAndServeUdp(outs))
	}()

	if webListener != nil {
		web.Store = st
		web.MainInfo.ClusterName = *clusterName
		// http handlers are installed in the init function of junta/web.
		go http.Serve(webListener, nil)
	}

	for {
		st.Apply(mg.Recv())
	}
}

func addPublicAddr(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	path := "/junta/info/"+ self +"/public-addr"
	mx, err := store.EncodeSet(path, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addHostname(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	path := "/junta/info/"+ self +"/hostname"
	mx, err := store.EncodeSet(path, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addMember(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/members/"+self, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func claimSlot(st *store.Store, seqn uint64, slot, self string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/slot/"+slot, self, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func claimLeader(st *store.Store, seqn uint64, self string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/leader", self, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addPing(st *store.Store, seqn uint64, v string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/ping", v, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}
<commit_msg>remove redundant type declarations<commit_after>package main

import (
	"flag"
	"fmt"
	"http"
	"junta/client"
	"junta/mon"
	"junta/paxos"
	"junta/server"
	"junta/store"
	"junta/util"
	"junta/web"
	"net"
	"os"
	"strings"
)

const (
	alpha = 50
)

// Flags
var (
	listenAddr = flag.String("l", "127.0.0.1:8046", "The address to bind to.")
	publishAddr = flag.String("L", "", "The address puslished for remote clients (default is listen address)")
	attachAddr = flag.String("a", "", "The address of another node to attach to.")
	webAddr = flag.String("w", ":8080", "Serve web requests on this address.")
	clusterName = flag.String("c", "local", "The non-empty cluster name.")
)

func activate(st *store.Store, self, prefix string, c *client.Client) {
	logger := util.NewLogger("activate")
	ch := make(chan store.Event)
	st.Watch("/junta/slot/*", ch)
	for ev := range ch {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			_, err := c.Set(prefix+ev.Path, self, ev.Cas)
			if err == nil {
				return
			}
			logger.Log(err)
		}
	}
}

func Usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] <cluster-name>\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\nOptions:\n")
	flag.PrintDefaults()
}

func main() {
	util.LogWriter = os.Stderr
	logger := util.NewLogger("main")

	flag.Parse()
	flag.Usage = Usage

	prefix := "/j/" + *clusterName

	if *listenAddr == "" {
		logger.Log("require a listen address")
		flag.Usage()
		os.Exit(1)
	}

	if *publishAddr == "" {
		publishAddr = listenAddr
	}

	var webListener net.Listener
	if *webAddr != "" {
		wl, err := net.Listen("tcp", *webAddr)
		if err != nil {
			panic(err)
		}
		webListener = wl
	}

	listener, err := net.Listen("tcp", *listenAddr)
	if err != nil {
		panic(err)
	}

	publishParts := strings.Split(*publishAddr, ":", 2)
	if len(publishParts) < 2 && publishParts[0] == "" {
		logger.Log("invalid publish address")
		flag.Usage()
		os.Exit(1)
	}

	outs := make(paxos.ChanPutCloserTo)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	seqn := uint64(0)
	if *attachAddr == "" { // we are the only node in a new cluster
		seqn = addPublicAddr(st, seqn + 1, self, *listenAddr)
		seqn = addHostname(st, seqn + 1, self, publishParts[0])
		seqn = addMember(st, seqn + 1, self, *listenAddr)
		seqn = claimSlot(st, seqn + 1, "1", self)
		seqn = claimLeader(st, seqn + 1, self)
		seqn = claimSlot(st, seqn + 1, "2", "")
		seqn = claimSlot(st, seqn + 1, "3", "")
		seqn = claimSlot(st, seqn + 1, "4", "")
		seqn = claimSlot(st, seqn + 1, "5", "")
		seqn = addPing(st, seqn + 1, "pong")

		cl, err = client.Dial(*listenAddr)
		if err != nil {
			panic(err)
		}
	} else {
		cl, err = client.Dial(*attachAddr)
		if err != nil {
			panic(err)
		}

		path := prefix + "/junta/info/"+ self +"/public-addr"
		_, err = cl.Set(path, *listenAddr, store.Clobber)
		if err != nil {
			panic(err)
		}

		path = prefix + "/junta/info/"+ self +"/hostname"
		_, err = cl.Set(path, os.Getenv("HOSTNAME"), store.Clobber)
		if err != nil {
			panic(err)
		}

		var snap string
		seqn, snap, err = cl.Join(self, *listenAddr)
		if err != nil {
			panic(err)
		}

		ch := make(chan store.Event)
		st.Wait(seqn + alpha, ch)
		st.Apply(1, snap)

		go func() {
			<-ch
			activate(st, self, prefix, cl)
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}
	mg := paxos.NewManager(self, seqn, alpha, st, outs)

	if *attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		for i := seqn + 1; i < seqn + alpha; i++ {
			go st.Apply(i, store.Nop)
		}
	}

	sv := &server.Server{*listenAddr, st, mg, self, prefix}

	go func() {
		panic(mon.Monitor(self, prefix, st, cl))
	}()

	go func() {
		panic(sv.Serve(listener))
	}()

	go func() {
		panic(sv.ListenAndServeUdp(outs))
	}()

	if webListener != nil {
		web.Store = st
		web.MainInfo.ClusterName = *clusterName
		// http handlers are installed in the init function of junta/web.
		go http.Serve(webListener, nil)
	}

	for {
		st.Apply(mg.Recv())
	}
}

func addPublicAddr(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	path := "/junta/info/"+ self +"/public-addr"
	mx, err := store.EncodeSet(path, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addHostname(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	path := "/junta/info/"+ self +"/hostname"
	mx, err := store.EncodeSet(path, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addMember(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/members/"+self, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func claimSlot(st *store.Store, seqn uint64, slot, self string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/slot/"+slot, self, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func claimLeader(st *store.Store, seqn uint64, self string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/leader", self, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addPing(st *store.Store, seqn uint64, v string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/ping", v, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"
	"net"
	"fmt"

	"junta/proto"
)

// Flags
var (
	id         *string = flag.String("i", "", "Node id to use.")
	listenAddr *string = flag.String("l", ":8040", "The address to bind to.")
	attachAddr *string = flag.String("a", "", "The address to bind to.")
)

// Globals
var (
	logger *log.Logger = log.New(
		os.Stderr, nil,
		"juntad: ",
		log.Lok | log.Lshortfile,
	)
)

func main() {
	flag.Parse()

	logger.Logf("binding to %s", *listenAddr)
	lisn, err := net.Listen("tcp", *listenAddr)
	if err != nil {
		logger.Log("unable to listen on %s: %s", *listenAddr, err)
		os.Exit(1)
	}
	logger.Logf("listening on %s", *listenAddr)

	for {
		conn, err := lisn.Accept()
		if err != nil {
			logger.Log("unable to accept on %s: %s", *listenAddr, err)
			continue
		}

		go func() {
			c := proto.NewConn(conn)
			_, parts, err := c.ReadRequest()
			if err != nil {
				logger.Log(err)
				return
			}
			fmt.Println(parts)
		}()
	}
}
<commit_msg>sick logger!<commit_after>package main

import (
	"flag"
	"log"
	"os"
	"net"
	"fmt"

	"junta/proto"
)

// Flags
var (
	id         *string = flag.String("i", "", "Node id to use.")
	listenAddr *string = flag.String("l", ":8040", "The address to bind to.")
	attachAddr *string = flag.String("a", "", "The address to bind to.")
)

func NewLogger(format string, a ... interface{}) *log.Logger {
	prefix := fmt.Sprintf(format, a)

	if prefix == "" {
		panic("always give a prefix!")
	}

	return log.New(
		os.Stderr, nil,
		"juntad: " + prefix + " ",
		log.Lok | log.Lshortfile,
	)
}

func main() {
	flag.Parse()

	logger := NewLogger("main")

	logger.Logf("binding to %s", *listenAddr)
	lisn, err := net.Listen("tcp", *listenAddr)
	if err != nil {
		logger.Log("unable to listen on %s: %s", *listenAddr, err)
		os.Exit(1)
	}
	logger.Logf("listening on %s", *listenAddr)

	for {
		conn, err := lisn.Accept()
		if err != nil {
			logger.Log("unable to accept on %s: %s", *listenAddr, err)
			continue
		}
		go serveConn(conn)
	}
}

func serveConn(conn net.Conn) {
	c := proto.NewConn(conn)
	_, parts, err := c.ReadRequest()
	logger := NewLogger("%v", conn.RemoteAddr())
	logger.Logf("accepted connection")
	if err != nil {
		logger.Log(err)
		return
	}
	logger.Logf("recvd req <%v>", parts)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"http"
	"net"
	"os"

	"junta/paxos"
	"junta/mon"
	"junta/store"
	"junta/util"
	"junta/client"
	"junta/server"
	"junta/web"
)

const (
	alpha = 50
)

// Flags
var (
	listenAddr *string = flag.String("l", "", "The address to bind to. Must correspond to a single public interface.")
	publishAddr *string = flag.String("p", "", "Address to publish in junta for client connections.")
	attachAddr *string = flag.String("a", "", "The address of another node to attach to.")
	webAddr *string = flag.String("w", "", "Serve web requests on this address.")
)

func activate(st *store.Store, self, prefix string, c *client.Client) {
	logger := util.NewLogger("activate")
	ch := make(chan store.Event)
	st.Watch("/junta/slot/*", ch)
	for ev := range ch {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			_, err := c.Set(prefix+ev.Path, self, ev.Cas)
			if err == nil {
				return
			}
			logger.Log(err)
		}
	}
}

func Usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] <cluster-name>\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\nOptions:\n")
	flag.PrintDefaults()
}

func main() {
	util.LogWriter = os.Stderr
	logger := util.NewLogger("main")

	flag.Parse()
	flag.Usage = Usage

	if len(flag.Args()) < 1 {
		logger.Log("require a cluster name")
		flag.Usage()
		os.Exit(1)
	}

	clusterName := flag.Arg(0)
	prefix := "/j/" + clusterName

	if *listenAddr == "" {
		logger.Log("require a listen address")
		flag.Usage()
		os.Exit(1)
	}

	if *publishAddr == "" {
		*publishAddr = *listenAddr
	}

	var webListener net.Listener
	if *webAddr != "" {
		wl, err := net.Listen("tcp", *webAddr)
		if err != nil {
			panic(err)
		}
		webListener = wl
	}

	listener, err := net.Listen("tcp", *listenAddr)
	if err != nil {
		panic(err)
	}

	outs := make(paxos.ChanPutCloserTo)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	seqn := uint64(0)
	if *attachAddr == "" { // we are the only node in a new cluster
		seqn = addPublicAddr(st, seqn + 1, self, *publishAddr)
		seqn = addHostname(st, seqn + 1, self, os.Getenv("HOSTNAME"))
		seqn = addMember(st, seqn + 1, self, *listenAddr)
		seqn = claimSlot(st, seqn + 1, "1", self)
		seqn = claimLeader(st, seqn + 1, self)
		seqn = claimSlot(st, seqn + 1, "2", "")
		seqn = claimSlot(st, seqn + 1, "3", "")
		seqn = claimSlot(st, seqn + 1, "4", "")
		seqn = claimSlot(st, seqn + 1, "5", "")
		seqn = addPing(st, seqn + 1, "pong")

		cl, err = client.Dial(*listenAddr)
		if err != nil {
			panic(err)
		}
	} else {
		cl, err = client.Dial(*attachAddr)
		if err != nil {
			panic(err)
		}

		path := prefix + "/junta/info/"+ self +"/public-addr"
		_, err = cl.Set(path, *publishAddr, store.Clobber)
		if err != nil {
			panic(err)
		}

		path = prefix + "/junta/info/"+ self +"/hostname"
		_, err = cl.Set(path, os.Getenv("HOSTNAME"), store.Clobber)
		if err != nil {
			panic(err)
		}

		var snap string
		seqn, snap, err = cl.Join(self, *listenAddr)
		if err != nil {
			panic(err)
		}

		ch := make(chan store.Event)
		st.Wait(seqn + alpha, ch)
		st.Apply(1, snap)

		go func() {
			<-ch
			activate(st, self, prefix, cl)
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}
	mg := paxos.NewManager(self, seqn, alpha, st, outs)

	if *attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		for i := seqn + 1; i < seqn + alpha; i++ {
			go st.Apply(i, store.Nop)
		}
	}

	sv := &server.Server{*listenAddr, st, mg, self, prefix}

	go func() {
		panic(mon.Monitor(self, prefix, st, cl))
	}()

	go func() {
		panic(sv.Serve(listener))
	}()

	go func() {
		panic(sv.ListenAndServeUdp(outs))
	}()

	if webListener != nil {
		web.Store = st
		web.MainInfo.ClusterName = clusterName
		// http handlers are installed in the init function of junta/web.
		go http.Serve(webListener, nil)
	}

	for {
		st.Apply(mg.Recv())
	}
}

func addPublicAddr(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	path := "/junta/info/"+ self +"/public-addr"
	mx, err := store.EncodeSet(path, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addHostname(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	path := "/junta/info/"+ self +"/hostname"
	mx, err := store.EncodeSet(path, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addMember(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/members/"+self, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func claimSlot(st *store.Store, seqn uint64, slot, self string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/slot/"+slot, self, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func claimLeader(st *store.Store, seqn uint64, self string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/leader", self, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addPing(st *store.Store, seqn uint64, v string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/ping", v, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}
<commit_msg>publishAddr is listenAddr - remove option<commit_after>package main

import (
	"flag"
	"fmt"
	"http"
	"net"
	"os"

	"junta/paxos"
	"junta/mon"
	"junta/store"
	"junta/util"
	"junta/client"
	"junta/server"
	"junta/web"
)

const (
	alpha = 50
)

// Flags
var (
	listenAddr *string = flag.String("l", "", "The address to bind to. Must correspond to a single public interface.")
	attachAddr *string = flag.String("a", "", "The address of another node to attach to.")
	webAddr *string = flag.String("w", "", "Serve web requests on this address.")
)

func activate(st *store.Store, self, prefix string, c *client.Client) {
	logger := util.NewLogger("activate")
	ch := make(chan store.Event)
	st.Watch("/junta/slot/*", ch)
	for ev := range ch {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			_, err := c.Set(prefix+ev.Path, self, ev.Cas)
			if err == nil {
				return
			}
			logger.Log(err)
		}
	}
}

func Usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] <cluster-name>\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\nOptions:\n")
	flag.PrintDefaults()
}

func main() {
	util.LogWriter = os.Stderr
	logger := util.NewLogger("main")

	flag.Parse()
	flag.Usage = Usage

	if len(flag.Args()) < 1 {
		logger.Log("require a cluster name")
		flag.Usage()
		os.Exit(1)
	}

	clusterName := flag.Arg(0)
	prefix := "/j/" + clusterName

	if *listenAddr == "" {
		logger.Log("require a listen address")
		flag.Usage()
		os.Exit(1)
	}

	var webListener net.Listener
	if *webAddr != "" {
		wl, err := net.Listen("tcp", *webAddr)
		if err != nil {
			panic(err)
		}
		webListener = wl
	}

	listener, err := net.Listen("tcp", *listenAddr)
	if err != nil {
		panic(err)
	}

	outs := make(paxos.ChanPutCloserTo)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	seqn := uint64(0)
	if *attachAddr == "" { // we are the only node in a new cluster
		seqn = addPublicAddr(st, seqn + 1, self, *listenAddr)
		seqn = addHostname(st, seqn + 1, self, os.Getenv("HOSTNAME"))
		seqn = addMember(st, seqn + 1, self, *listenAddr)
		seqn = claimSlot(st, seqn + 1, "1", self)
		seqn = claimLeader(st, seqn + 1, self)
		seqn = claimSlot(st, seqn + 1, "2", "")
		seqn = claimSlot(st, seqn + 1, "3", "")
		seqn = claimSlot(st, seqn + 1, "4", "")
		seqn = claimSlot(st, seqn + 1, "5", "")
		seqn = addPing(st, seqn + 1, "pong")

		cl, err = client.Dial(*listenAddr)
		if err != nil {
			panic(err)
		}
	} else {
		cl, err = client.Dial(*attachAddr)
		if err != nil {
			panic(err)
		}

		path := prefix + "/junta/info/"+ self +"/public-addr"
		_, err = cl.Set(path, *listenAddr, store.Clobber)
		if err != nil {
			panic(err)
		}

		path = prefix + "/junta/info/"+ self +"/hostname"
		_, err = cl.Set(path, os.Getenv("HOSTNAME"), store.Clobber)
		if err != nil {
			panic(err)
		}

		var snap string
		seqn, snap, err = cl.Join(self, *listenAddr)
		if err != nil {
			panic(err)
		}

		ch := make(chan store.Event)
		st.Wait(seqn + alpha, ch)
		st.Apply(1, snap)

		go func() {
			<-ch
			activate(st, self, prefix, cl)
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}
	mg := paxos.NewManager(self, seqn, alpha, st, outs)

	if *attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		for i := seqn + 1; i < seqn + alpha; i++ {
			go st.Apply(i, store.Nop)
		}
	}

	sv := &server.Server{*listenAddr, st, mg, self, prefix}

	go func() {
		panic(mon.Monitor(self, prefix, st, cl))
	}()

	go func() {
		panic(sv.Serve(listener))
	}()

	go func() {
		panic(sv.ListenAndServeUdp(outs))
	}()

	if webListener != nil {
		web.Store = st
		web.MainInfo.ClusterName = clusterName
		// http handlers are installed in the init function of junta/web.
		go http.Serve(webListener, nil)
	}

	for {
		st.Apply(mg.Recv())
	}
}

func addPublicAddr(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	path := "/junta/info/"+ self +"/public-addr"
	mx, err := store.EncodeSet(path, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addHostname(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	path := "/junta/info/"+ self +"/hostname"
	mx, err := store.EncodeSet(path, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addMember(st *store.Store, seqn uint64, self, addr string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/members/"+self, addr, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func claimSlot(st *store.Store, seqn uint64, slot, self string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/slot/"+slot, self, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func claimLeader(st *store.Store, seqn uint64, self string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/junta/leader", self, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}

func addPing(st *store.Store, seqn uint64, v string) uint64 {
	// TODO pull out path as a const
	mx, err := store.EncodeSet("/ping", v, store.Missing)
	if err != nil {
		panic(err)
	}
	st.Apply(seqn, mx)
	return seqn
}
<|endoftext|>


<commit_before>package cmd

import (
	"gopkg.in/urfave/cli.v2"
)

func mainActivity(ctx *cli.Context) error {
	client := getClient(ctx)
	if err := client.Login(); err != nil {
		return err
	}
	return nil
}
<commit_msg>extend main activity<commit_after>package cmd

import (
	"fmt"

	"gopkg.in/urfave/cli.v2"
)

func mainActivity(ctx *cli.Context) error {
	fmt.Println("main activity")
	client := getClient(ctx)
	if err := client.Login(); err != nil {
		return err
	}
	setTokens(ctx, client.Tokens)
	saveTokens(ctx, client.Tokens)
	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// runCmd represents the run command
var runCmd = &cobra.Command{
	Use:   "run",
	Short: "Run relay",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Hello!")
	},
}

func init() {
	rootCmd.AddCommand(runCmd)
}
<commit_msg>basic command to launch router<commit_after>package cmd

import (
	"fmt"

	"github.com/mmcloughlin/pearl"
	"github.com/mmcloughlin/pearl/log"
	"github.com/mmcloughlin/pearl/torconfig"
	"github.com/spf13/cobra"
)

// runCmd represents the run command
var runCmd = &cobra.Command{
	Use:   "run",
	Short: "Run relay",
	RunE: func(cmd *cobra.Command, args []string) error {
		return run()
	},
}

func init() {
	rootCmd.AddCommand(runCmd)
}

func run() error {
	platform := torconfig.NewPlatformHostOS("pearl", "0.1")
	config := &torconfig.Config{
		Nickname: "pearl",
		ORPort:   9001,
		Platform: platform.String(),
	}

	logger := log.NewDebug()

	r, err := pearl.NewRouter(config, logger)
	if err != nil {
		return err
	}

	desc := r.Descriptor()
	doc, err := desc.Document()
	if err != nil {
		return err
	}

	fmt.Println(string(doc.Encode()))

	go func() {
		r.Run()
	}()

	authority := "127.0.0.1:7000"
	err = desc.PublishToAuthority(authority)
	if err != nil {
		return err
	}
	logger.With("authority", authority).Info("published descriptor")

	select {}
}
<|endoftext|>


<commit_before>// Copyright 2017 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// root2csv converts the content of a ROOT TTree to a CSV file.
//
//  Usage of root2csv:
//    -f string
//      	path to input ROOT file name
//    -o string
//      	path to output CSV file name (default "output.csv")
//    -t string
//      	name of the tree to convert (default "tree")
//
// By default, root2csv will write out a CSV file with ';' as a column delimiter.
// root2csv ignores the branches of the TTree that are not supported by CSV:
//  - slices/arrays
//  - C++ objects
//
// Example:
//  $> root2csv -o out.csv -t tree -f testdata/small-flat-tree.root
//  $> head out.csv
//  ## Automatically generated from "testdata/small-flat-tree.root"
//  Int32;Int64;UInt32;UInt64;Float32;Float64;Str;N
//  0;0;0;0;0;0;evt-000;0
//  1;1;1;1;1;1;evt-001;1
//  2;2;2;2;2;2;evt-002;2
//  3;3;3;3;3;3;evt-003;3
//  4;4;4;4;4;4;evt-004;4
//  5;5;5;5;5;5;evt-005;5
//  6;6;6;6;6;6;evt-006;6
//  7;7;7;7;7;7;evt-007;7
package main

import (
	"flag"
	"fmt"
	"log"
	"reflect"
	"strings"

	"go-hep.org/x/hep/csvutil"
	"go-hep.org/x/hep/groot"
	_ "go-hep.org/x/hep/groot/riofs/plugin/http"
	_ "go-hep.org/x/hep/groot/riofs/plugin/xrootd"
	"go-hep.org/x/hep/groot/rtree"
)

func main() {
	log.SetPrefix("root2csv: ")
	log.SetFlags(0)

	fname := flag.String("f", "", "path to input ROOT file name")
	oname := flag.String("o", "output.csv", "path to output CSV file name")
	tname := flag.String("t", "tree", "name of the tree to convert")

	flag.Parse()

	if *fname == "" {
		flag.Usage()
		log.Fatalf("missing input ROOT filename argument")
	}

	f, err := groot.Open(*fname)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	obj, err := f.Get(*tname)
	if err != nil {
		log.Fatal(err)
	}

	tree, ok := obj.(rtree.Tree)
	if !ok {
		log.Fatalf("object %q in file %q is not a rtree.Tree", *tname, *fname)
	}

	var nt = ntuple{n: tree.Entries()}
	log.Printf("scanning leaves...")
	for _, leaf := range tree.Leaves() {
		if leaf.Kind() == reflect.String {
			nt.add(leaf.Name(), leaf)
			continue
		}
		if leaf.Class() == "TLeafElement" { // FIXME(sbinet): find a better, type-safe way
			log.Printf(">>> %q %v not supported", leaf.Name(), leaf.Class())
			continue
		}
		if leaf.LeafCount() != nil {
			log.Printf(">>> %q []%v not supported", leaf.Name(), leaf.TypeName())
			continue
		}
		if leaf.Len() > 1 {
			log.Printf(">>> %q [%d]%v not supported", leaf.Name(), leaf.Len(), leaf.TypeName())
			continue
		}
		nt.add(leaf.Name(), leaf)
	}
	log.Printf("scanning leaves... [done]")

	sc, err := rtree.NewTreeScannerVars(tree, nt.args...)
	if err != nil {
		log.Fatal(err)
	}
	defer sc.Close()

	nrows := 0
	for sc.Next() {
		err = sc.Scan(nt.vars...)
		if err != nil {
			log.Fatal(err)
		}
		nt.fill()
		nrows++
	}

	tbl, err := csvutil.Create(*oname)
	if err != nil {
		log.Fatal(err)
	}
	defer tbl.Close()
	tbl.Writer.Comma = ';'

	names := make([]string, len(nt.cols))
	for i, col := range nt.cols {
		names[i] = col.name
	}
	err = tbl.WriteHeader(fmt.Sprintf(
		"## Automatically generated from %q\n%s\n",
		*fname,
		strings.Join(names, string(tbl.Writer.Comma)),
	))
	if err != nil {
		log.Fatalf("could not write header: %v", err)
	}

	row := make([]interface{}, len(nt.cols))
	for irow := 0; irow < nrows; irow++ {
		for i, col := range nt.cols {
			row[i] = col.slice.Index(irow).Interface()
		}
		err = tbl.WriteRow(row...)
		if err != nil {
			log.Fatalf("error writing row %d: %v", irow, err)
		}
	}

	err = tbl.Close()
	if err != nil {
		log.Fatalf("could not close CSV file: %v", err)
	}
}

type ntuple struct {
	n    int64
	cols []column
	args []rtree.ScanVar
	vars []interface{}
}

func (nt *ntuple) add(name string, leaf rtree.Leaf) {
	n := len(nt.cols)
	nt.cols = append(nt.cols, newColumn(name, leaf, nt.n))
	col := &nt.cols[n]
	nt.args = append(nt.args, rtree.ScanVar{Name: name, Leaf: leaf.Name()})
	nt.vars = append(nt.vars, col.data.Addr().Interface())
}

func (nt *ntuple) fill() {
	for i := range nt.cols {
		col := &nt.cols[i]
		col.fill()
	}
}

type column struct {
	name  string
	i     int64
	leaf  rtree.Leaf
	etype reflect.Type
	shape []int
	data  reflect.Value
	slice reflect.Value
}

func newColumn(name string, leaf rtree.Leaf, n int64) column {
	etype := leaf.Type()
	shape := []int{int(n)}
	if leaf.Len() > 1 && leaf.Kind() != reflect.String {
		etype = reflect.ArrayOf(leaf.Len(), etype)
		shape = append(shape, leaf.Len())
	}
	rtype := reflect.SliceOf(etype)
	return column{
		name:  name,
		i:     0,
		leaf:  leaf,
		etype: etype,
		shape: shape,
		data:  reflect.New(etype).Elem(),
		slice: reflect.MakeSlice(rtype, int(n), int(n)),
	}
}

func (col *column) fill() {
	col.slice.Index(int(col.i)).Set(col.data)
	col.i++
}
<commit_msg>cmd/root2csv: handle TLeafElements with builtins<commit_after>// Copyright 2017 The go-hep Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// root2csv converts the content of a ROOT TTree to a CSV file.
//
//  Usage of root2csv:
//    -f string
//      	path to input ROOT file name
//    -o string
//      	path to output CSV file name (default "output.csv")
//    -t string
//      	name of the tree to convert (default "tree")
//
// By default, root2csv will write out a CSV file with ';' as a column delimiter.
// root2csv ignores the branches of the TTree that are not supported by CSV:
//  - slices/arrays
//  - C++ objects
//
// Example:
//  $> root2csv -o out.csv -t tree -f testdata/small-flat-tree.root
//  $> head out.csv
//  ## Automatically generated from "testdata/small-flat-tree.root"
//  Int32;Int64;UInt32;UInt64;Float32;Float64;Str;N
//  0;0;0;0;0;0;evt-000;0
//  1;1;1;1;1;1;evt-001;1
//  2;2;2;2;2;2;evt-002;2
//  3;3;3;3;3;3;evt-003;3
//  4;4;4;4;4;4;evt-004;4
//  5;5;5;5;5;5;evt-005;5
//  6;6;6;6;6;6;evt-006;6
//  7;7;7;7;7;7;evt-007;7
package main

import (
	"flag"
	"fmt"
	"log"
	"reflect"
	"strings"

	"go-hep.org/x/hep/csvutil"
	"go-hep.org/x/hep/groot"
	_ "go-hep.org/x/hep/groot/riofs/plugin/http"
	_ "go-hep.org/x/hep/groot/riofs/plugin/xrootd"
	"go-hep.org/x/hep/groot/rtree"
)

func main() {
	log.SetPrefix("root2csv: ")
	log.SetFlags(0)

	fname := flag.String("f", "", "path to input ROOT file name")
	oname := flag.String("o", "output.csv", "path to output CSV file name")
	tname := flag.String("t", "tree", "name of the tree to convert")

	flag.Parse()

	if *fname == "" {
		flag.Usage()
		log.Fatalf("missing input ROOT filename argument")
	}

	f, err := groot.Open(*fname)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()

	obj, err := f.Get(*tname)
	if err != nil {
		log.Fatal(err)
	}

	tree, ok := obj.(rtree.Tree)
	if !ok {
		log.Fatalf("object %q in file %q is not a rtree.Tree", *tname, *fname)
	}

	var nt = ntuple{n: tree.Entries()}
	log.Printf("scanning leaves...")
	for _, leaf := range tree.Leaves() {
		kind := leaf.Type().Kind()
		switch kind {
		case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
			log.Printf(">>> %q %v not supported (%v)", leaf.Name(), leaf.Class(), kind)
			continue
		case reflect.Bool,
			reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
			reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
			reflect.Float32, reflect.Float64,
			reflect.String:
		default:
			log.Printf(">>> %q %v not supported (%v) (unknown!)", leaf.Name(), leaf.Class(), kind)
			continue
		}

		nt.add(leaf.Name(), leaf)
	}
	log.Printf("scanning leaves... [done]")

	sc, err := rtree.NewTreeScannerVars(tree, nt.args...)
	if err != nil {
		log.Fatal(err)
	}
	defer sc.Close()

	nrows := 0
	for sc.Next() {
		err = sc.Scan(nt.vars...)
		if err != nil {
			log.Fatal(err)
		}
		nt.fill()
		nrows++
	}

	tbl, err := csvutil.Create(*oname)
	if err != nil {
		log.Fatal(err)
	}
	defer tbl.Close()
	tbl.Writer.Comma = ';'

	names := make([]string, len(nt.cols))
	for i, col := range nt.cols {
		names[i] = col.name
	}
	err = tbl.WriteHeader(fmt.Sprintf(
		"## Automatically generated from %q\n%s\n",
		*fname,
		strings.Join(names, string(tbl.Writer.Comma)),
	))
	if err != nil {
		log.Fatalf("could not write header: %v", err)
	}

	row := make([]interface{}, len(nt.cols))
	for irow := 0; irow < nrows; irow++ {
		for i, col := range nt.cols {
			row[i] = col.slice.Index(irow).Interface()
		}
		err = tbl.WriteRow(row...)
		if err != nil {
			log.Fatalf("error writing row %d: %v", irow, err)
		}
	}

	err = tbl.Close()
	if err != nil {
		log.Fatalf("could not close CSV file: %v", err)
	}
}

type ntuple struct {
	n    int64
	cols []column
	args []rtree.ScanVar
	vars []interface{}
}

func (nt *ntuple) add(name string, leaf rtree.Leaf) {
	n := len(nt.cols)
	nt.cols = append(nt.cols, newColumn(name, leaf, nt.n))
	col := &nt.cols[n]
	nt.args = append(nt.args, rtree.ScanVar{Name: name, Leaf: leaf.Name()})
	nt.vars = append(nt.vars, col.data.Addr().Interface())
}

func (nt *ntuple) fill() {
	for i := range nt.cols {
		col := &nt.cols[i]
		col.fill()
	}
}

type column struct {
	name  string
	i     int64
	leaf  rtree.Leaf
	etype reflect.Type
	shape []int
	data  reflect.Value
	slice reflect.Value
}

func newColumn(name string, leaf rtree.Leaf, n int64) column {
	etype := leaf.Type()
	shape := []int{int(n)}
	if leaf.Len() > 1 && leaf.Kind() != reflect.String {
		etype = reflect.ArrayOf(leaf.Len(), etype)
		shape = append(shape, leaf.Len())
	}
	rtype := reflect.SliceOf(etype)
	return column{
		name:  name,
		i:     0,
		leaf:  leaf,
		etype: etype,
		shape: shape,
		data:  reflect.New(etype).Elem(),
		slice: reflect.MakeSlice(rtype, int(n), int(n)),
	}
}

func (col *column) fill() {
	col.slice.Index(int(col.i)).Set(col.data)
	col.i++
}
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cmds

import (
	"fmt"

	"github.com/fabric8io/gofabric8/client"
	"github.com/fabric8io/gofabric8/util"
	"github.com/spf13/cobra"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

type cleanUpTenantFlags struct {
	confirm bool
}

// NewCmdCleanUpTenant delete files in the tenants content repository
func NewCmdCleanUpTenant(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "tenant",
		Short: "Hard delete of your tenant pipelines, apps, jobs and releases",
		Long:  `Hard delete of your tenant pipelines, apps, jobs and releases`,

		Run: func(cmd *cobra.Command, args []string) {
			p := cleanUpTenantFlags{}
			if cmd.Flags().Lookup(yesFlag).Value.String() == "true" {
				p.confirm = true
			}
			err := p.cleanTenant(f)
			if err != nil {
				util.Fatalf("%s", err)
			}
			return
		},
	}
	return cmd
}

func (p *cleanUpTenantFlags) cleanTenant(f *cmdutil.Factory) error {
	c, cfg := client.NewClient(f)
	ns, _, _ := f.DefaultNamespace()
	oc, _ := client.NewOpenShiftClient(cfg)
	initSchema()

	userNS, err := detectCurrentUserNamespace(ns, c, oc)
	if err != nil {
		return err
	}
	jenkinsNS := fmt.Sprintf("%s-jenkins", userNS)

	if !p.confirm {
		confirm := ""
		util.Warn("WARNING this is destructive and will remove all of your tenant pipelines, apps and releases!\n")
		util.Info("for your tenant: ")
		util.Successf("%s", userNS)
		util.Info(" running in namespace: ")
		util.Successf("%s\n", jenkinsNS)
		util.Warn("\nContinue [y/N]: ")
		fmt.Scanln(&confirm)
		if confirm != "y" {
			util.Warn("Aborted\n")
			return nil
		}
	}

	err = (&cleanUpMavenLocalRepoFlags{
		confirm: true,
	}).cleanMavenLocalRepo(f)
	if err != nil {
		return err
	}
	fmt.Println("")

	err = (&cleanUpContentRepoFlags{
		confirm: true,
	}).cleanContentRepo(f)
	if err != nil {
		return err
	}
	fmt.Println("")

	err = (&cleanUpJenkinsFlags{
		confirm: true,
	}).cleanUpJenkins(f)
	if err != nil {
		return err
	}
	fmt.Println("")

	err = (&cleanUpAppsFlags{
		confirm: true,
	}).cleanApps(f)
	if err != nil {
		return err
	}
	util.Info("\n\nCompleted cleaning the tenant resource\n")
	return nil
}
<commit_msg>lets try zap builds first in case quota is stopping jenkins master from starting<commit_after>/**
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cmds

import (
	"fmt"

	"github.com/fabric8io/gofabric8/client"
	"github.com/fabric8io/gofabric8/util"
	"github.com/spf13/cobra"
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)

type cleanUpTenantFlags struct {
	confirm bool
}

// NewCmdCleanUpTenant delete files in the tenants content repository
func NewCmdCleanUpTenant(f *cmdutil.Factory) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "tenant",
		Short: "Hard delete of your tenant pipelines, apps, jobs and releases",
		Long:  `Hard delete of your tenant pipelines, apps, jobs and releases`,

		Run: func(cmd *cobra.Command, args []string) {
			p := cleanUpTenantFlags{}
			if cmd.Flags().Lookup(yesFlag).Value.String() == "true" {
				p.confirm = true
			}
			err := p.cleanTenant(f)
			if err != nil {
				util.Fatalf("%s", err)
			}
			return
		},
	}
	return cmd
}

func (p *cleanUpTenantFlags) cleanTenant(f *cmdutil.Factory) error {
	c, cfg := client.NewClient(f)
	ns, _, _ := f.DefaultNamespace()
	oc, _ := client.NewOpenShiftClient(cfg)
	initSchema()

	userNS, err := detectCurrentUserNamespace(ns, c, oc)
	if err != nil {
		return err
	}
	jenkinsNS := fmt.Sprintf("%s-jenkins", userNS)

	if !p.confirm {
		confirm := ""
		util.Warn("WARNING this is destructive and will remove all of your tenant pipelines, apps and releases!\n")
		util.Info("for your tenant: ")
		util.Successf("%s", userNS)
		util.Info(" running in namespace: ")
		util.Successf("%s\n", jenkinsNS)
		util.Warn("\nContinue [y/N]: ")
		fmt.Scanln(&confirm)
		if confirm != "y" {
			util.Warn("Aborted\n")
			return nil
		}
	}

  err = (&cleanUpAppsFlags{
 		confirm: true,
 	}).cleanApps(f)
 	if err != nil {
 		return err
 	}
	err = (&cleanUpMavenLocalRepoFlags{
		confirm: true,
	}).cleanMavenLocalRepo(f)
	if err != nil {
		return err
	}
	fmt.Println("")

	err = (&cleanUpContentRepoFlags{
		confirm: true,
	}).cleanContentRepo(f)
	if err != nil {
		return err
	}
	fmt.Println("")

	err = (&cleanUpJenkinsFlags{
		confirm: true,
	}).cleanUpJenkins(f)
	if err != nil {
		return err
	}
	fmt.Println("")

	util.Info("\n\nCompleted cleaning the tenant resource\n")
	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"github.com/spf13/cobra/cobra/tpl"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
)

// Project contains name, license and paths to projects.
type Project struct {
	// v2
	PkgName      string
	Copyright    string
	AbsolutePath string
	Legal        License
	Viper        bool
	AppName      string

	// v1
	absPath string
	cmdPath string
	srcPath string
	license License
	name    string
}

func (p *Project) Create() error {

	// create main.go
	mainFile, err := os.Create(fmt.Sprintf("%s/main.go", p.AbsolutePath))
	if err != nil {
		return err
	}
	defer mainFile.Close()

	mainTemplate := template.Must(template.New("main").Parse(string(tpl.MainTemplate())))
	err = mainTemplate.Execute(mainFile, p)
	if err != nil {
		return err
	}

	// create cmd/root.go
	if _, err = os.Stat(fmt.Sprintf("%s/cmd", p.AbsolutePath)); os.IsNotExist(err) {
		os.Mkdir("cmd", 0751)
	}
	rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath))
	if err != nil {
		return err
	}
	defer rootFile.Close()

	rootTemplate := template.Must(template.New("root").Parse(string(tpl.RootTemplate())))
	err = rootTemplate.Execute(rootFile, p)
	if err != nil {
		return err
	}

	// create license
	createLicenseFile(p.Legal, p.AbsolutePath)
	return nil
}

// NewProject returns Project with specified project name.
func NewProject(projectName string) *Project {
	if projectName == "" {
		er("can't create project with blank name")
	}

	p := new(Project)
	p.name = projectName

	// 1. Find already created protect.
	p.absPath = findPackage(projectName)

	// 2. If there are no created project with this path, and user is in GOPATH,
	// then use GOPATH/src/projectName.
	if p.absPath == "" {
		wd, err := os.Getwd()
		if err != nil {
			er(err)
		}
		for _, srcPath := range srcPaths {
			goPath := filepath.Dir(srcPath)
			if filepathHasPrefix(wd, goPath) {
				p.absPath = filepath.Join(srcPath, projectName)
				break
			}
		}
	}

	// 3. If user is not in GOPATH, then use (first GOPATH)/src/projectName.
	if p.absPath == "" {
		p.absPath = filepath.Join(srcPaths[0], projectName)
	}

	return p
}

// findPackage returns full path to existing go package in GOPATHs.
func findPackage(packageName string) string {
	if packageName == "" {
		return ""
	}

	for _, srcPath := range srcPaths {
		packagePath := filepath.Join(srcPath, packageName)
		if exists(packagePath) {
			return packagePath
		}
	}

	return ""
}

// NewProjectFromPath returns Project with specified absolute path to
// package.
func NewProjectFromPath(absPath string) *Project {
	if absPath == "" {
		er("can't create project: absPath can't be blank")
	}
	if !filepath.IsAbs(absPath) {
		er("can't create project: absPath is not absolute")
	}

	// If absPath is symlink, use its destination.
	fi, err := os.Lstat(absPath)
	if err != nil {
		er("can't read path info: " + err.Error())
	}
	if fi.Mode()&os.ModeSymlink != 0 {
		path, err := os.Readlink(absPath)
		if err != nil {
			er("can't read the destination of symlink: " + err.Error())
		}
		absPath = path
	}

	p := new(Project)
	p.absPath = strings.TrimSuffix(absPath, findCmdDir(absPath))
	p.name = filepath.ToSlash(trimSrcPath(p.absPath, p.SrcPath()))
	return p
}

// trimSrcPath trims at the beginning of absPath the srcPath.
func trimSrcPath(absPath, srcPath string) string {
	relPath, err := filepath.Rel(srcPath, absPath)
	if err != nil {
		er(err)
	}
	return relPath
}

// License returns the License object of project.
func (p *Project) License() License {
	if p.license.Text == "" && p.license.Name != "None" {
		p.license = getLicense()
	}
	return p.license
}

// Name returns the name of project, e.g. "github.com/spf13/cobra"
func (p Project) Name() string {
	return p.name
}

// CmdPath returns absolute path to directory, where all commands are located.
func (p *Project) CmdPath() string {
	if p.absPath == "" {
		return ""
	}
	if p.cmdPath == "" {
		p.cmdPath = filepath.Join(p.absPath, findCmdDir(p.absPath))
	}
	return p.cmdPath
}

// findCmdDir checks if base of absPath is cmd dir and returns it or
// looks for existing cmd dir in absPath.
func findCmdDir(absPath string) string {
	if !exists(absPath) || isEmpty(absPath) {
		return "cmd"
	}

	if isCmdDir(absPath) {
		return filepath.Base(absPath)
	}

	files, _ := filepath.Glob(filepath.Join(absPath, "c*"))
	for _, file := range files {
		if isCmdDir(file) {
			return filepath.Base(file)
		}
	}

	return "cmd"
}

// isCmdDir checks if base of name is one of cmdDir.
func isCmdDir(name string) bool {
	name = filepath.Base(name)
	for _, cmdDir := range []string{"cmd", "cmds", "command", "commands"} {
		if name == cmdDir {
			return true
		}
	}
	return false
}

// AbsPath returns absolute path of project.
func (p Project) AbsPath() string {
	return p.absPath
}

// SrcPath returns absolute path to $GOPATH/src where project is located.
func (p *Project) SrcPath() string {
	if p.srcPath != "" {
		return p.srcPath
	}
	if p.absPath == "" {
		p.srcPath = srcPaths[0]
		return p.srcPath
	}

	for _, srcPath := range srcPaths {
		if filepathHasPrefix(p.absPath, srcPath) {
			p.srcPath = srcPath
			break
		}
	}

	return p.srcPath
}

func filepathHasPrefix(path string, prefix string) bool {
	if len(path) <= len(prefix) {
		return false
	}
	if runtime.GOOS == "windows" {
		// Paths in windows are case-insensitive.
		return strings.EqualFold(path[0:len(prefix)], prefix)
	}
	return path[0:len(prefix)] == prefix

}
<commit_msg>vgo - generate license<commit_after>package cmd

import (
	"fmt"
	"github.com/spf13/cobra/cobra/tpl"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
)

// Project contains name, license and paths to projects.
type Project struct {
	// v2
	PkgName      string
	Copyright    string
	AbsolutePath string
	Legal        License
	Viper        bool
	AppName      string

	// v1
	absPath string
	cmdPath string
	srcPath string
	license License
	name    string
}

func (p *Project) Create() error {

	// create main.go
	mainFile, err := os.Create(fmt.Sprintf("%s/main.go", p.AbsolutePath))
	if err != nil {
		return err
	}
	defer mainFile.Close()

	mainTemplate := template.Must(template.New("main").Parse(string(tpl.MainTemplate())))
	err = mainTemplate.Execute(mainFile, p)
	if err != nil {
		return err
	}

	// create cmd/root.go
	if _, err = os.Stat(fmt.Sprintf("%s/cmd", p.AbsolutePath)); os.IsNotExist(err) {
		os.Mkdir("cmd", 0751)
	}
	rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath))
	if err != nil {
		return err
	}
	defer rootFile.Close()

	rootTemplate := template.Must(template.New("root").Parse(string(tpl.RootTemplate())))
	err = rootTemplate.Execute(rootFile, p)
	if err != nil {
		return err
	}

	// create license
	return createLicenseFile(p.Legal, p.AbsolutePath)
}

func (p *Project) createLicenseFile() error {
	data := map[string]interface{}{
		"copyright": copyrightLine(),
	}
	licenseFile, err := os.Create(fmt.Sprintf("%s/LICENSE", p.AbsolutePath))
	if err != nil {
		return err
	}

	licenseTemplate := template.Must(template.New("license").Parse(p.Legal.Text))
	return licenseTemplate.Execute(licenseFile, data)
}

//func createLicenseFile(license License, path string) {
//	data := make(map[string]interface{})
//	data["copyright"] = copyrightLine()
//
//	// Generate license template from text and data.
//	text, err := executeTemplate(license.Text, data)
//	if err != nil {
//		er(err)
//	}
//
//	// Write license text to LICENSE file.
//	err = writeStringToFile(filepath.Join(path, "LICENSE"), text)
//	if err != nil {
//		er(err)
//	}
//}

// NewProject returns Project with specified project name.
func NewProject(projectName string) *Project {
	if projectName == "" {
		er("can't create project with blank name")
	}

	p := new(Project)
	p.name = projectName

	// 1. Find already created protect.
	p.absPath = findPackage(projectName)

	// 2. If there are no created project with this path, and user is in GOPATH,
	// then use GOPATH/src/projectName.
	if p.absPath == "" {
		wd, err := os.Getwd()
		if err != nil {
			er(err)
		}
		for _, srcPath := range srcPaths {
			goPath := filepath.Dir(srcPath)
			if filepathHasPrefix(wd, goPath) {
				p.absPath = filepath.Join(srcPath, projectName)
				break
			}
		}
	}

	// 3. If user is not in GOPATH, then use (first GOPATH)/src/projectName.
	if p.absPath == "" {
		p.absPath = filepath.Join(srcPaths[0], projectName)
	}

	return p
}

// findPackage returns full path to existing go package in GOPATHs.
func findPackage(packageName string) string {
	if packageName == "" {
		return ""
	}

	for _, srcPath := range srcPaths {
		packagePath := filepath.Join(srcPath, packageName)
		if exists(packagePath) {
			return packagePath
		}
	}

	return ""
}

// NewProjectFromPath returns Project with specified absolute path to
// package.
func NewProjectFromPath(absPath string) *Project {
	if absPath == "" {
		er("can't create project: absPath can't be blank")
	}
	if !filepath.IsAbs(absPath) {
		er("can't create project: absPath is not absolute")
	}

	// If absPath is symlink, use its destination.
	fi, err := os.Lstat(absPath)
	if err != nil {
		er("can't read path info: " + err.Error())
	}
	if fi.Mode()&os.ModeSymlink != 0 {
		path, err := os.Readlink(absPath)
		if err != nil {
			er("can't read the destination of symlink: " + err.Error())
		}
		absPath = path
	}

	p := new(Project)
	p.absPath = strings.TrimSuffix(absPath, findCmdDir(absPath))
	p.name = filepath.ToSlash(trimSrcPath(p.absPath, p.SrcPath()))
	return p
}

// trimSrcPath trims at the beginning of absPath the srcPath.
func trimSrcPath(absPath, srcPath string) string {
	relPath, err := filepath.Rel(srcPath, absPath)
	if err != nil {
		er(err)
	}
	return relPath
}

// License returns the License object of project.
func (p *Project) License() License {
	if p.license.Text == "" && p.license.Name != "None" {
		p.license = getLicense()
	}
	return p.license
}

// Name returns the name of project, e.g. "github.com/spf13/cobra"
func (p Project) Name() string {
	return p.name
}

// CmdPath returns absolute path to directory, where all commands are located.
func (p *Project) CmdPath() string {
	if p.absPath == "" {
		return ""
	}
	if p.cmdPath == "" {
		p.cmdPath = filepath.Join(p.absPath, findCmdDir(p.absPath))
	}
	return p.cmdPath
}

// findCmdDir checks if base of absPath is cmd dir and returns it or
// looks for existing cmd dir in absPath.
func findCmdDir(absPath string) string {
	if !exists(absPath) || isEmpty(absPath) {
		return "cmd"
	}

	if isCmdDir(absPath) {
		return filepath.Base(absPath)
	}

	files, _ := filepath.Glob(filepath.Join(absPath, "c*"))
	for _, file := range files {
		if isCmdDir(file) {
			return filepath.Base(file)
		}
	}

	return "cmd"
}

// isCmdDir checks if base of name is one of cmdDir.
func isCmdDir(name string) bool {
	name = filepath.Base(name)
	for _, cmdDir := range []string{"cmd", "cmds", "command", "commands"} {
		if name == cmdDir {
			return true
		}
	}
	return false
}

// AbsPath returns absolute path of project.
func (p Project) AbsPath() string {
	return p.absPath
}

// SrcPath returns absolute path to $GOPATH/src where project is located.
func (p *Project) SrcPath() string {
	if p.srcPath != "" {
		return p.srcPath
	}
	if p.absPath == "" {
		p.srcPath = srcPaths[0]
		return p.srcPath
	}

	for _, srcPath := range srcPaths {
		if filepathHasPrefix(p.absPath, srcPath) {
			p.srcPath = srcPath
			break
		}
	}

	return p.srcPath
}

func filepathHasPrefix(path string, prefix string) bool {
	if len(path) <= len(prefix) {
		return false
	}
	if runtime.GOOS == "windows" {
		// Paths in windows are case-insensitive.
		return strings.EqualFold(path[0:len(prefix)], prefix)
	}
	return path[0:len(prefix)] == prefix

}
<|endoftext|>