Skip to content

Commit

Permalink
Update Comments for All functions and Improve Error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
SwayKh committed Sep 20, 2024
1 parent f73bc65 commit 14b8295
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 35 deletions.
26 changes: 14 additions & 12 deletions cmd/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ import (
"github.com/SwayKh/linksym/pkg/linker"
)

// Add function, which handles the Add subcommand and handles all scenarios of
// file paths provided.
// Handling one argument is simple enough, just Move the
// file to cwd and link it.
// Handling 2 arguments creates lots of different scenario of combination of
// files and directory, and handling the special scenario of a File/Dir which is
// already moved by the user, and just needs to be linked, Skipping the move of
// file step of the Linking process
func Add(args []string) error {
switch len(args) {

case 1:
// Set first arg source path, get absolute path, check if it exists, set the
// destination path as cwd+filename of source path
source, err := filePathInfo(args[0])
if err != nil {
return err
Expand All @@ -27,10 +33,6 @@ func Add(args []string) error {
return linker.MoveAndLink(source.AbsPath, destinationPath, source.IsDir)

case 2:
// set first and second args as source and destination path, get absolute
// paths, check if the paths exist, plus handle the special case of source
// path not existing but destination path exists, hence creating a link
// without the moving the files
destination, err := filePathInfo(args[1])
if err != nil {
return err
Expand All @@ -55,7 +57,7 @@ func Add(args []string) error {
return linker.MoveAndLink(source.AbsPath, destination.AbsPath, isSourceDir)

case isSourceFile && isDestinationFile:
return fmt.Errorf("Destination path %s already exists", destination.AbsPath)
return fmt.Errorf("Destination file %s already exists", destination.AbsPath)

// Link Source file to Destination by using path as File or Directory based
// on trailling / provided with argument
Expand All @@ -72,7 +74,7 @@ func Add(args []string) error {

// Can't link a Directory to a File
case isSourceDir && isDestinationFile:
return fmt.Errorf("Can't Link a Directory %s to a File %s", source.AbsPath, destination.AbsPath)
return fmt.Errorf("Can't link a Directory: %s to a File: %s", source.AbsPath, destination.AbsPath)

// Link Source directory to Destination by using path as File or Directory
// based on trailling / provided with argument. But can't link a Directory
Expand All @@ -82,10 +84,11 @@ func Add(args []string) error {
destination.AbsPath = appendToDestinationPath(source.AbsPath, destination.AbsPath)
return linker.MoveAndLink(source.AbsPath, destination.AbsPath, isSourceDir)
} else {
return fmt.Errorf("Can't Link a Directory %s to a File %s", source.AbsPath, destination.AbsPath)
return fmt.Errorf("Can't link a Directory: %s to a File: %s", source.AbsPath, destination.AbsPath)
}

// Source Doesn't exists(Can be file or dir), But Destination does, and is a file
// Source Doesn't exists, But Destination does, and is a file and the Source
// can be a directory path or a file path
case !source.Exists && isDestinationFile:
if source.HasSlash {
// Given Source path has a trailing /, hence it's a directory
Expand All @@ -102,14 +105,13 @@ func Add(args []string) error {
return linker.Link(source.AbsPath, destination.AbsPath)
}
// Else Source is a file, and destination is a directory
return fmt.Errorf("Can't Link a file %s to a directory %s", source.AbsPath, destination.AbsPath)
return fmt.Errorf("Can't link a File: %s to a Directory: %s", source.AbsPath, destination.AbsPath)

// Source and Destination Both Don't Exist
case !source.Exists && !destination.Exists:
return fmt.Errorf("Source and Destination paths don't exist, Nothing to Link")

default:
// return fmt.Errorf("Unable to link %s to %s. \nEither the Source or Destination path don't exist, \nor There is a mismatch of types, eg - Directory to a file", source.AbsPath, destination.AbsPath)
return fmt.Errorf("Invalid arguments provided")
}

Expand Down
1 change: 1 addition & 0 deletions cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ var (
ConfigPath string
)

// Setup the Flags for the CLI
func CreateFlags() {
// Handle both -h and --help with one boolean
HelpFlag = flag.Bool("h", false, "Show help")
Expand Down
1 change: 1 addition & 0 deletions cmd/linksym.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/SwayKh/linksym/pkg/config"
)

// Load config, Setup up Global variables and handle all subcommand switching
func Run() error {
var err error

Expand Down
4 changes: 4 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ func SetupDirectories() error {
return nil
}

// Create a array of Path provided and a Link Name which is appended in the
// Records of the global Configuration Struct
func AddRecord(sourcePath, destinationPath string) error {
record := record{}

Expand All @@ -61,6 +63,8 @@ func AddRecord(sourcePath, destinationPath string) error {
return nil
}

// Remove a Record of Link Name and Path array from the global configuration
// struct, which is written to file at the end of program execution
func RemoveRecord(i int) {
Configuration.Records = append(Configuration.Records[:i], Configuration.Records[i+1:]...)
}
26 changes: 16 additions & 10 deletions pkg/config/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,30 @@ import (
"gopkg.in/yaml.v3"
)

// Load the configuration from .linksym.yaml configuration file and unmarshall
// it into the global Configuration variable, and un-alias all paths
func LoadConfig() error {
// Check if config file exists
if fileExists, _, err := CheckFile(ConfigPath); err != nil {
return fmt.Errorf("Error checking if .linksym.yaml exists: \n %w", err)
return fmt.Errorf("Error checking if .linksym.yaml exists: %w", err)
} else if !fileExists {
return fmt.Errorf("No .linksym.yaml file found, please run linksym init: \n %w", err)
return fmt.Errorf("No .linksym.yaml file found. Please run linksym init.")
}

file, err := os.Open(ConfigPath)
if err != nil {
return fmt.Errorf("Error opening config file: %s: \n%w", ConfigPath, err)
return fmt.Errorf("Error opening config file: %s ", ConfigPath)
}
defer file.Close()

data, err := io.ReadAll(file)
if err != nil {
return fmt.Errorf("Error reading data from config file: \n%w", err)
return fmt.Errorf("Error reading data from config file: %w", err)
}

err = yaml.Unmarshal(data, &Configuration)
if err != nil {
return fmt.Errorf("Error loading data to appConfig{}: \n%w", err)
return fmt.Errorf("Error loading data to appConfig{}: %w", err)
}

Configuration.InitDirectory = expandPath(Configuration.InitDirectory)
Expand All @@ -43,6 +45,8 @@ func LoadConfig() error {
return nil
}

// Write the Configuration struct data to .linksym.yaml file after aliasing all
// paths with ~ and $init_directory
func WriteConfig() error {
Configuration.InitDirectory = aliasPath(Configuration.InitDirectory, true)

Expand All @@ -55,20 +59,22 @@ func WriteConfig() error {

data, err := yaml.Marshal(&Configuration)
if err != nil {
return fmt.Errorf("Error marshalling data from appConfig{}: \n%w", err)
return fmt.Errorf("Error marshalling data from Configuration{}: %w", err)
}

err = os.WriteFile(ConfigPath, data, 0o644)
if err != nil {
return fmt.Errorf("Error writing record to config file: \n%w", err)
return fmt.Errorf("Error writing record to config file: %w", err)
}
return nil
}

// Create a default config file with empty records and Current working directory
// variable for Init directory
func InitialiseConfig() error {
err := SetupDirectories()
if err != nil {
return fmt.Errorf("Initialising Env: \n%w", err)
return fmt.Errorf("Initialising Env: %w", err)
}

InitDirectory, err := os.Getwd()
Expand All @@ -85,12 +91,12 @@ func InitialiseConfig() error {

data, err := yaml.Marshal(&configuration)
if err != nil {
return fmt.Errorf("Error marshalling Init Data from appConfig{}: \n%w", err)
return fmt.Errorf("Error marshalling Init Data from Configuration{}: %w", err)
}

err = os.WriteFile(ConfigPath, data, 0o644)
if err != nil {
return fmt.Errorf("Error writing data to config file: \n%w", err)
return fmt.Errorf("Error writing data to config file: %w", err)
}
return nil
}
5 changes: 4 additions & 1 deletion pkg/config/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ func CheckFile(path string) (bool, os.FileInfo, error) {
if errors.Is(err, os.ErrNotExist) {
return false, nil, nil
} else {
return false, nil, fmt.Errorf("Error getting file info: \n%w", err)
return false, nil, fmt.Errorf("Error getting file info: %w", err)
}
}
return true, fileInfo, nil
}

// Expand the ~ and $init_directory variables to their respective values
func expandPath(path string) string {
if strings.HasPrefix(path, "$init_directory") {
path = strings.Replace(path, "$init_directory", Configuration.InitDirectory, 1)
Expand All @@ -29,6 +30,8 @@ func expandPath(path string) string {
return path
}

// Create aliases of ~ and $init_directory to make the paths and the
// configurations more portable
func aliasPath(path string, skipInitDir bool) string {
if strings.HasPrefix(path, HomeDirectory) {
path = strings.Replace(path, HomeDirectory, "~", 1)
Expand Down
31 changes: 19 additions & 12 deletions pkg/linker/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ import (
"github.com/SwayKh/linksym/pkg/config"
)

// Move the source file to destination and creates a symlink at the source
// pointing towards the destination path
func MoveAndLink(sourcePath, destinationPath string, isDirectory bool) error {
// If path is a directory, Rename it
if isDirectory {
err := os.Rename(sourcePath, destinationPath)
if err != nil {
return fmt.Errorf("Couldn't rename directory %s to %s: \n%w", sourcePath, destinationPath, err)
return fmt.Errorf("Couldn't link directory %s to %s: %w", sourcePath, destinationPath, err)
}
} else {
// If path is a file, create a file at new location, copy it over, and
// delete original file. This method allows better handling when linking
// across file system than just renaming files
err := moveFile(sourcePath, destinationPath)
if err != nil {
return err
Expand All @@ -32,10 +31,12 @@ func MoveAndLink(sourcePath, destinationPath string, isDirectory bool) error {
return nil
}

// Create a symlink of source path at the destination path, and create a record
// of it
func Link(sourcePath, destinationPath string) error {
err := os.Symlink(destinationPath, sourcePath)
if err != nil {
return fmt.Errorf("Couldn't create symlink %s: \n%w", destinationPath, err)
return fmt.Errorf("Couldn't create symlink %s: %w", destinationPath, err)
}

err = config.AddRecord(sourcePath, destinationPath)
Expand All @@ -45,6 +46,8 @@ func Link(sourcePath, destinationPath string) error {
return nil
}

// Remove the symlink file at the source, move the destination file to the
// original source path. Undoing the MoveAndLink function basically
func UnLink(sourcePath, destinationPath string, isDirectory bool) error {
err := deleteFile(sourcePath)
if err != nil {
Expand All @@ -54,7 +57,7 @@ func UnLink(sourcePath, destinationPath string, isDirectory bool) error {
if isDirectory {
err := os.Rename(destinationPath, sourcePath)
if err != nil {
return fmt.Errorf("Couldn't rename directory %s to %s: \n%w", sourcePath, destinationPath, err)
return fmt.Errorf("Couldn't move directory %s to %s: %w", sourcePath, destinationPath, err)
}
} else {
err := moveFile(destinationPath, sourcePath)
Expand All @@ -65,26 +68,29 @@ func UnLink(sourcePath, destinationPath string, isDirectory bool) error {
return nil
}

// Create a a file at the destination, copy all contents of the source to the
// destination and then remove the source. This method allows better handling
// when linking across file system than just renaming files
func moveFile(source, destination string) error {
src, err := os.Open(source)
if err != nil {
return fmt.Errorf("Failed to source file: %s: \n%w", source, err)
return fmt.Errorf("Failed to open file: %s: %w", source, err)
}
defer src.Close()

dst, err := os.Create(destination)
if err != nil {
return fmt.Errorf("Failed to create file %s: \n%w", destination, err)
return fmt.Errorf("Failed to create file %s: %w", destination, err)
}
defer dst.Close()

_, err = io.Copy(dst, src)
if err != nil {
return fmt.Errorf("Failed to copy file %s to %s: \n%w", source, destination, err)
return fmt.Errorf("Failed to copy file %s to %s: %w", source, destination, err)
}
err = dst.Sync()
if err != nil {
return fmt.Errorf("Failed to write file %s to disk: \n%w", destination, err)
return fmt.Errorf("Failed to write file %s to disk: %w", destination, err)
}

err = deleteFile(source)
Expand All @@ -94,13 +100,14 @@ func moveFile(source, destination string) error {
return nil
}

// Delete the file at the given path
func deleteFile(path string) error {
err := os.Remove(path)
if err != nil {
if os.IsPermission(err) {
return fmt.Errorf("Failed to Remove file %s\n Please run with elevated privileges", path)
return fmt.Errorf("Failed to Remove file %s. Please run with elevated privileges", path)
} else {
return fmt.Errorf("Failed to Remove file %s: \n%w", path, err)
return fmt.Errorf("Failed to Remove file %s: %w", path, err)
}
}
return nil
Expand Down

0 comments on commit 14b8295

Please sign in to comment.