lib/dotter/cli.rb in dotter_dotfiles-0.2.0 vs lib/dotter/cli.rb in dotter_dotfiles-0.3.0

- old
+ new

@@ -3,188 +3,203 @@ require 'dotter/gitrepo' require 'dotter/version' require 'dotter/configuration' require 'dotter/package' require 'dotter/publicgitrepo' +require 'dotter/foreigngitrepo' require 'pathname' +require 'git' module Dotter -class CLI < Thor - include Utilities - desc "version", "Print the dotter version" - def version - puts "This is dotter #{Dotter::VERSION}" - end - desc "init", "Initialise the directory structure for ~/dotfiles" - def init - puts "Initialising ~/dotfiles" - puts "Creating the dotfiles directory." - FileUtils.mkpath(dotfiles_path) - go_to_dotfiles - puts "Creating the directory for the combined public dotfiles." - FileUtils.mkpath('public') - puts "Creating an initial package for dotter." - FileUtils.mkpath('dotter/.dotter/gitrepos') - FileUtils.mkpath('dotter/.dotter/indexes/') - # If we don't do this now, we'll get a nasty exception if we ever access the configuration. - FIleUtils.touch('dotter/.dotter/Dotfile') - end - desc "list", "List all packages present in ~/dotfiles" - def list - puts "List of packages in ~/dotfiles" - all_package_names.each do |package| - puts package - end - end - desc "stow PACKAGE", "Stow the given package name." - def stow(package) - package = Package.new(package) - if package.stowed? - error "Package #{package} is already stowed." - exit(1) - end - puts "Stowing package #{package}" - puts package.stow - end - desc "unstow PACKAGE", "Unstow the given package name." - def unstow(package) - package = Package.new(package) - if package.unstowed? - error "Package #{package} is not stowed." - exit(1) - end - puts "Unstowing package #{package}" - puts package.unstow - end - desc "track PACKAGE", "Begin tracking the given package with Git" - def track(package) - puts "Initialising Git repository for package #{package}" - package = Package.new(package) - package.track - puts "Repository for package #{package} initialised. Git's metadata is stored in #{package.repo.metadata_path.to_s}" - puts "Creating an initial snapshot to serve as a starting point." - repo = package.repo - repo.add('.') - repo.commit_all("Initial snapshot of the package's contents") - puts "Initial snapshot created." - end - desc "publish PACKAGE", "Make a package available in your public dotfiles repository" - def publish(package) - puts "Making package #{package} public" - public_repo = PublicGitRepo.new - puts public_repo.add_package(package) - end - desc "unpublish PACKAGE", "Make a package private after publishing it." - def unpublish(package) - puts "Making package #{package} private again" - public_repo = PublicGitRepo.new - public_repo.remove_package(package) - end - method_option :commit_message, :required => true, :aliases => "-m" - method_option :all, :type => :boolean, :aliases => "-a" - desc "commit PACKAGE", "Commit your changes to a Git-tracked package." - def commit(package) - package = Package.new(package) - if package.untracked? - error "Package #{package} is not tracked by Git." - exit 1 - end - puts "Committing the changes to package #{package} with commit message #{options.commit_message}." - commit_message = options.commit_message - repo = package.repo - if options.all - repo.commit_all(commit_message) - else - repo.commit(commit_message) - end - end - desc "update PACKAGE", "Updates the specified package" - def update(package) - puts "Updating the contents / symlinks for package #{package}" - package = Package.new(package) - if package.unstowed? - error "Package #{package} is not stowed and therefore cannot be updated." - exit 1 - end - package.update - end - desc "update_all", "Updates all stowed packages." - def update_all() - puts "Updating all stowed packages" - all_packages = [] - all_package_names.each do |package| - all_packages.push(Package.new(package.to_s)) - end - stowed_packages = all_packages.select { |package| package.stowed? } - stowed_packages.each do |package| - puts "Updating #{package}" - package.update - end - end - desc "import PATH PACKAGE", "Imports a file or directory into the specified package" - def import(path, package) - puts "Importing #{path} into package #{package}" - filepath = Pathname.new(File.expand_path(path)) - packagepath = package_path(package) - if not Dir.exist?(packagepath.to_s) then FileUtils.mkpath(packagepath.to_s) end - homepath = Pathname.new(File.expand_path('~')) - relative_filepath = filepath.relative_path_from(homepath) - complete_path = packagepath + relative_filepath - FileUtils.copy(File.expand_path(path), complete_path.to_s) - puts "File imported successfully. Update the package to make the symlink." - end - desc "import_repo REPO_URL PACKAGE", "Clones the specified git repository as the contents of the specified Package." - def import_repo(repo_url, package) - puts "Cloning repository #{repo_url} into package #{package}" - end - desc "clone REPO_URL", "Clones the dotfiles / packages of the specified repository into ~/dotfiles. Will overwrite any existing data." - def clone(repo_url) - puts "Cloning repository #{repo_url} directly into ~/dotfiles" - end - desc "status PACKAGE", "Obtain the repository status of a Git-tracked package." - def status(package) - package = Package.new(package) - if package.untracked? - error "Package #{package} is not tracked by Git." - exit 1 - end - metadata_path = repo_path(package.to_s) - metadata_indexes_path = index_path(package.to_s) - # Punt because it does this better than ruby-git. - system({"GIT_DIR" => metadata_path.to_s, "GIT_INDEX_FILE" => metadata_indexes_path.to_s}, "git status") - end - desc "add PACKAGE FILE", "Add a file from a package to the next commit of that package." - def add(package,file) - package = Package.new(package) - if package.untracked? - error "Package #{package} is not tracked by Git." - exit 1 - end - puts "Marking #{file} to be committed for package #{package}" - repo = package.repo - repo.add(file) + class CLI < Thor + include Utilities + desc 'version', 'Print the dotter version' + def version + puts "This is dotter #{Dotter::VERSION}" end - desc "reset PACKAGE", "Reset what will be commmitted in the next commit to the given package." - def reset(package) - package = Package.new(package) - if package.untracked? - error "Package #{package} is not tracked by Git." - exit 1 - end - puts "Resetting what will be committed to package #{package}" - repo = package.repo - repo.reset() - end - desc "log PACKAGE", "View the commit log of a package." - def log(package) - package = Package.new(package) - if package.untracked? - error "Package #{package} is not tracked by Git." - exit 1 - end - puts "Obtaining the log of package #{package}" - repo = package.repo - repo.log.each do |commit| - puts "[#{commit.date}] #{commit.message} (#{commit.author.name})" - end - end -end + desc 'init', 'Initialise the directory structure for ~/dotfiles' + def init + puts 'Initialising ~/dotfiles' + puts 'Creating the dotfiles directory.' + FileUtils.mkpath(dotfiles_path) + go_to_dotfiles + puts 'Creating the directory for the combined public dotfiles.' + FileUtils.mkpath('public') + puts 'Creating an initial package for dotter.' + FileUtils.mkpath('dotter/.dotter/gitrepos') + FileUtils.mkpath('dotter/.dotter/indexes/') + # If we don't do this now, we'll get a nasty exception if we ever access the configuration. + FileUtils.touch('dotter/.dotter/Dotfile') + end + desc 'list', 'List all packages present in ~/dotfiles' + def list + puts 'List of packages in ~/dotfiles' + all_package_names.each do |package| + puts package + end + end + desc 'stow PACKAGE', 'Stow the given package name.' + def stow(package) + package = Package.new(package) + if package.stowed? + error "Package #{package} is already stowed." + exit(1) + end + puts "Stowing package #{package}" + puts package.stow + end + desc 'unstow PACKAGE', 'Unstow the given package name.' + def unstow(package) + package = Package.new(package) + if package.unstowed? + error "Package #{package} is not stowed." + exit(1) + end + puts "Unstowing package #{package}" + puts package.unstow + end + desc 'track PACKAGE', 'Begin tracking the given package with Git' + def track(package) + puts "Initialising Git repository for package #{package}" + package = Package.new(package) + package.track + puts "Repository for package #{package} initialised. Git's metadata is stored in #{package.repo.metadata_path}" + puts 'Creating an initial snapshot to serve as a starting point.' + repo = package.repo + repo.add('.') + repo.commit_all("Initial snapshot of the package's contents") + puts 'Initial snapshot created.' + end + desc 'publish PACKAGE', 'Make a package available in your public dotfiles repository' + def publish(package) + puts "Making package #{package} public" + public_repo = PublicGitRepo.new + puts public_repo.add_package(package) + end + desc 'unpublish PACKAGE', 'Make a package private after publishing it.' + def unpublish(package) + puts "Making package #{package} private again" + public_repo = PublicGitRepo.new + public_repo.remove_package(package) + end + method_option :commit_message, required: true, aliases: '-m' + method_option :all, type: :boolean, aliases: '-a' + desc 'commit PACKAGE', 'Commit your changes to a Git-tracked package.' + def commit(package) + package = Package.new(package) + if package.untracked? + error "Package #{package} is not tracked by Git." + exit 1 + end + puts "Committing the changes to package #{package} with commit message #{options.commit_message}." + commit_message = options.commit_message + repo = package.repo + if options.all + repo.commit_all(commit_message) + else + repo.commit(commit_message) + end + end + desc 'update PACKAGE', 'Updates the specified package. For packages imported from external repositories, also updates the repository.' + def update(package) + puts "Updating the contents / symlinks for package #{package}" + package = Package.new(package) + if package.unstowed? + error "Package #{package} is not stowed and therefore cannot be updated." + exit 1 + end + package.update + end + desc 'update_all', 'Updates all stowed packages.' + def update_all + puts 'Updating all stowed packages' + all_packages = [] + all_package_names.each do |package| + all_packages.push(Package.new(package.to_s)) + end + stowed_packages = all_packages.select(&:stowed?) + stowed_packages.each do |package| + puts "Updating #{package}" + package.update + end + end + desc 'import PATH PACKAGE', 'Imports a file or directory into the specified package' + def import(path, package) + puts "Importing #{path} into package #{package}" + filepath = Pathname.new(File.expand_path(path)) + packagepath = package_path(package) + FileUtils.mkpath(packagepath.to_s) unless Dir.exist?(packagepath.to_s) + homepath = Pathname.new(File.expand_path('~')) + relative_filepath = filepath.relative_path_from(homepath) + complete_path = packagepath + relative_filepath + FileUtils.copy(File.expand_path(path), complete_path.to_s) + puts 'File imported successfully. Update the package to make the symlink.' + end + desc 'import_repo REPO_URL PACKAGE', 'Clones the specified git repository as the contents of the specified Package.' + def import_repo(repo_url, package) + puts "Cloning repository #{repo_url} into package #{package}" + ForeignGitRepo.new(package, true, repo_url) + puts "Repository #{repo_url} successfully cloned into #{package}." + # We need to manually set the package as tracked to avoid calling init() again. + config = Configuration.new + config.track(package) + config.set_type(package, 'git_repo') + config.set_url(package, repo_url) + end + desc 'clone REPO_URL', 'Clones the dotfiles / packages of the specified repository into ~/dotfiles. Will overwrite any existing data.' + def clone(repo_url) + puts "Cloning repository #{repo_url} directly into ~/dotfiles" + repo = Git.clone(repo_url, @@dotfiles_path.to_s) + puts "Due to implementation difficulties, all the the commit history and state information will be lost." + go_to_dotfiles + `rm -rf .git` + `rm -rf dotter/*` + `touch dotter/Dotfile` + end + desc 'status PACKAGE', 'Obtain the repository status of a Git-tracked package.' + def status(package) + package = Package.new(package) + if package.untracked? + error "Package #{package} is not tracked by Git." + exit 1 + end + metadata_path = repo_path(package.to_s) + metadata_indexes_path = index_path(package.to_s) + # Punt because it does this better than ruby-git. + system({ 'GIT_DIR' => metadata_path.to_s, 'GIT_INDEX_FILE' => metadata_indexes_path.to_s }, 'git status') + end + desc 'add PACKAGE FILE', 'Add a file from a package to the next commit of that package.' + def add(package, file) + package = Package.new(package) + if package.untracked? + error "Package #{package} is not tracked by Git." + exit 1 + end + puts "Marking #{file} to be committed for package #{package}" + repo = package.repo + repo.add(file) + end + desc 'reset PACKAGE', 'Reset what will be commmitted in the next commit to the given package.' + def reset(package) + package = Package.new(package) + if package.untracked? + error "Package #{package} is not tracked by Git." + exit 1 + end + puts "Resetting what will be committed to package #{package}" + repo = package.repo + repo.reset + end + desc 'log PACKAGE', 'View the commit log of a package.' + def log(package) + package = Package.new(package) + if package.untracked? + error "Package #{package} is not tracked by Git." + exit 1 + end + puts "Obtaining the log of package #{package}" + repo = package.repo + repo.log.each do |commit| + puts "[#{commit.date}] #{commit.message} (#{commit.author.name})" + end + end + end end