Code Monkey home page Code Monkey logo

dotfiles-framework's Introduction

.-files

Note: This repository contains the management code for installing packages, and not the actual "dotfiles" themselves. See Dotfiles.

Synopsis

dotfiles repositories are commonly used for synchronising files related to *nix shell environments. In addition to offering a synchronisation source, this piece of software also helps set up some more sought utilities and tools.

usage: dotfiles [-h] [-l | -i | -u] [package [package ...]]

Usage

The dotfiles.py main script handles installing the environment. Specify the packages to install.

If no packages are specified, the list and description of packages will be shown. If package names are specified, the default action is to install the packages.

Listing status for a particular package is possible if --list is explicitly specified: dotfiles --list foo bar.

⚠️ Note: This tool is intended to be used when a new user profile is created, such as when a new machine is installed.

Package globber

Multiple packages belonging to a package "group" can be selected by saying group.* or group.__ALL__.

Package sources

Multiple package sources can be given to Dotfiles. To edit the package configuration, use the built-in editor by calling

dotfiles --edit-sources

which will allow you to manually add, remove, move the sources.

The package sources are forming a priority list. When installing a package foo, it will be installed from the first source it is found.

Default sources

By default, the manager framework will use the following 2 package sources, in order:

  1. Your ~/Dotfiles/packages/ directory.
  2. The author's own Dotfiles repository.

Uninstalling packages

To uninstall packages, specify --uninstall before the package names:

dotfiles --uninstall foo

Package description details

Packages are present across a number of source root directories, where an arbitrary hierarchy can be present.

A package is any directory which contains a (valid) package.json file. Subpackages are translated from filesystem hierarchy to logical hierarchy via ., i.e. tools/system/package.json denotes the tools.system package.

Package descriptor files are YAMLs which contain the directives describing installation and handling of the package. Any other file is disregarded by the tool unless explicitly used, e.g. being the source of a copy operation.

The user-specific package source root configuration is parsed and expanded at the start of the invocation into special directories under ~/.cache and ~/.local/share. When a package name foo is requested, every package source is queried in the order configured, until one source is found, or it is realised the package does not exist. This resolution order is true for every package name lookup, so it applies to dependency queries, too.

Configuration directives

description (string)

Contains a free form textual description for the package which is printed in the "help" when dotfiles.py is invoked without any arguments.

dependencies (list of other package names)

The logical names of packages which must be installed before the installation of the current package could begin.

depend on parent (boolean, default: true)

Whether the package should implicitly depend on the parent (e.g. for tools.system, parent is tools), assuming the parent is a valid package.

support (boolean, default: false)

Support packages are packages which have all the necessary directives to perform an installation, but are NOT meant to do persistent changes to the user's environment and files.

Support packages can be depended upon, but may not be directly installed by the user. A support package's "installed" status will not be saved. Support packages may not have uninstall actions.

Packages with internal in their name (such as internal.mypkg) will automatically be considered as support packages.

Conditions (if and if not)

The package descriptor might take the if and if not keys, which specifies a list of strings, each associated with a condition. (See the table below for the options.)

Conditions for the entire package require satisfaction, without which the package will NOT be visible to the installer.

description: A package that can only be installed if 'sudo'.
if:
  - superuser
install:
  - action: shell
    command: "sudo echo 'Hey root!'"

Action directives may specify a list of conditions, with the $if and $if not meta-arguments. The conditions in the $if list (positive conditions) must all be satisfied, and none of the conditions in the $if not (negative conditions) list may be satisfied for the action to execute. If the conditions aren't as described for the action, the action will be skipped, but the rest of the actions will be executed. $if and $if not can both be specified on the same action. If neither is specified, the action is not conditional, and will always execute.

    - action: print
      $if:
        - superuser
      text: "I have sudo!"
    - action: print
      $if not:
        - superuser
      text: "I do not have sudo!"
    - action: print
      $if:
        - superuser
      $if not:
        - superuser
      text: "Impossible to execute... hopefully."

The contents of the package-level and the action-level condition lists are the same:

Condition Semantics
superuser Turns one action into a conditional action which is only executed if the user presents sudo rights.

Action directives

The installation of a package consists of two separate phases. Before the installation of the first package, a temporary $SESSION_DIR is created where temporary resources may be shared between packages. This directory is deleted at the end of execution of all installs. The usage of this feature is discouraged unless absolutely necessary.

Action directives are laid out in the package descriptor YAML file as shown below. Each phase has a list of key-value tuples, which will be executed in the order they are added. Each tuple must have an action argument which defines the type/kind of the action to run.

The rest of the arguments to specify are specific to the action type identifier. All the arguments that are not meta-arguments (starting with $) are specific to the action type identifier.

prepare:
    - action: shell
      command: echo "True"

prepare (optional)

First, the package's configuration and external dependencies are obtained. This is called the preparation phase.

At the beginning of this phase, the executing environment switches into a temporary directory. In most directives, $TEMPORARY_DIR can be used to refer to this directory when specifying a path.

Action Arguments Semantics Failure condition
copy resource path (string) Copy the file or directory from the package's resources (where package.yaml is) to the temporary directory path is invalid or OS-level permission error occurs
git clone repository (URL string) Obtain a clone of the repository by calling git git clone process fails
print text (string) Emit the message text to the user on the standard output.
shell command (string) Execute command in a shell Non-zero return
shell all commands (list of strings) Execute every command in order At least one command returns non-zero
shell any commands (list of strings) Execute the commands in order until one succeeds None of the commands returns zero

install

The installation starts from the packages/foo/bar/ directory (for package foo.bar). This phase is the main phase where changes to the user's files should be done.

In most directives, $TEMPORARY_DIR can be used to refer to the prepare phase's directory when specifying a path. (This may only be done if there was a prepare phase for the package!)

$PACKAGE_DIR refers to the directory where the package's metadata file (package.yaml) and additional resources are.

Action Arguments Semantics Failure condition
copy file (string), to (string) Copies file to the to path OS-level error
copy files (list of string), to (string), from (string, default: $PACKAGE_DIR), prefix (string, default: empty) As if copy was done for all element of files understood relative to from; to must be the destination directory, optionally prepending prefix to each destination filename OS-level error, to isn't an existing directory
copy tree dir (string), to (string) Copies the contents of dir to the to directory, to is created by this call OS-level error, to is an existing directory
make dirs dirs (list of strings) Creates the directories specified, and their parents if they don't exist OS-level error happens at creating a directory
remove file (string), ignore missing (boolean, default: true) Same as remove for Uninstall, but saves the original in the backup for later restoration see failure conditions for remove in Uninstall
remove files (list of string), ignore missing (boolean, default: true) Same as remove for Uninstall, but saves the original in the backup for later restoration see failure conditions for remove in Uninstall
remove where (string), file or files, ignore missing as above Same as remove for Uninstall, but saves the original in the backup for later restoration see failure conditions for remove in Uninstall
replace at (string), with file (string), with files (list of strings), from (string, default: empty), prefix (string, default: empty) Does the same as copy but also prepares restoring (at uninstall) the original target files if they existed see failure conditions for copy
print text (string) Emit the message text to the user on the standard output.
shell command (string) Execute command in a shell Non-zero return
shell all commands (list of strings) Execute every command in order At least one command returns non-zero
shell any commands (list of strings) Execute the commands in order until one succeeds None of the commands returns zero
symlink file (string), to (string), relative (boolean, default: false) Same as copy, but creates a symbolic link instead; if relative is true, the symbolic link will be created relatively from its target location. see failure conditions for copy
symlink files (list of strings), to (string), from (string, default: $PACKAGE_DIR), prefix (string, default: empty), relative (boolean, default: false) Same as copy, but create symbolic links instead; if relative is true, the symbolic links will be created relatively from their target location. see failure conditions for copy

uninstall

Uninstall starts from the directory that corresponds to $PACKAGE_DIR, but contains the files that were present in this directory at installation, not what are currently present on the system. This means that the state of package.yaml and the resource files are kept intact even if the packages/ directory on the system is updated.

In uninstall mode, $PACKAGE_DIR refers to this archived directory.

⚠️ Note! The "original" $PACKAGE_DIR is not accessible during uninstall.

Action Arguments Semantics Failure condition
remove file (string), ignore missing (boolean, default: true) Removes the specified file if it exists, raising an error if ignore missing is false; file must be an absolute path OS-level error happens at removal
remove files (list of strings, ignore missing (boolean, default: true) Removes all files specified, all files must be specified as an absolute path OS-level error happens at removal
remove where (string), file or files, ignore missing as above As above, but file or files may be a relative path, understood relative to where, where must be an existing directory's absolute path OS-level error, where isn't an existing directory
remove dirs dirs (list of strings) Removes the specified directory, if it is empty OS-level error happens at removing a directory
remove tree dir (string) Removes the tree (all subdirectories and files) under dir OS-level error, dir isn't an existing directory
restore file (string) Restores the version of the file (which must be an absolute path) that was present when the package was installed, if such version exists OS-level error
restore files (list of strings) Calls restore for each file in files OS-level error
print text (string) Emit the message text to the user on the standard output.
shell command (string) Execute command in a shell Non-zero return
shell all commands (list of strings) Execute every command in order At least one command returns non-zero
shell any commands (list of strings) Execute the commands in order until one succeeds None of the commands returns zero
Automatic uninstall actions for install directives

Certain install directives can automatically be mapped to uninstall actions. At the uninstall of a package, the corresponding actions are executed in reverse order (compared to the order of install directives).

If automatic uninstall actions were generated for a package's install, they are executed after the manually written uninstall directives are executed.

install action uninstall action Comment
copy remove file and files are translated in a reasonable manner, where is not filled automatically, paths containing environment variables are kept as such for uninstall!
copy tree(dir, to) remove tree(to)
make dirs(dirs) remove dirs(dirs)
remove restore file and files are translated in a reasonable manner, where is not filled automatically, paths containing environment variables are kept as such for uninstall!
replace restore with file and with files are translated in a reasonable manner, at is ignored as paths are translated into absolute paths but retain environment variables
symlink remove see details for copy

Transformers

Automatic transformation of the executed actions might be beneficial in some circumstances. All transformers are enabled with the --X flag, followed by the transformer's name (with dashes).

Explicitly disallowing transformers per-action

To forbid a transformer from running for an action, add its name set to false under the $transform meta-argument.

install:
  - action: copy
    file: foo
    to: bar
    $transform:
      copies as symlinks: false

copies-as-symlinks

Instead of executing copy-like directives during install normally, use the symlink action to set up symbolic links. The links will target the original files in the package source. This allows easy versioning of configuration file changes if the source is a versioned repository, as the original package source tree will have the files modified.

dotfiles-framework's People

Contributors

whisperity avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar

dotfiles-framework's Issues

Installation of packages from outside sources

The package descriptions are currently part of the repository and there is no option to specify a package from outside (i.e. not in this repo) sources.
The outside source could be a git repository with a standard layout, or maybe a git repository with additional path-segments which specify the package descriptor JSON files.

Support `replace` of files in non-existent directories

Using

- action: replace
  at: $HOME/.oh-my-zsh/custom/config.theme.zsh
  with file: config.theme.zsh

with ~/.oh-my-zsh not having been created (due to an ongoing change setting the location of that directory elsewhere...), the replace action fails as it can not back up a non-existent file from under a non-existent directory.

2023-09-26T13:17:10.6351634Z #23 32.46 Fail zsh.powerline: Install failed.
2023-09-26T13:17:10.6352126Z #23 32.46 'where' must be an existing directory, when given.
2023-09-26T13:17:10.6352520Z #23 32.46 Traceback (most recent call last):
2023-09-26T13:17:10.6352956Z #23 32.46   File "/opt/Dotfiles/dotfiles/actions/install.py", line 106, in _install
2023-09-26T13:17:10.6353434Z #23 32.46     package.execute_install(user_context, condition_engine,
2023-09-26T13:17:10.6353899Z #23 32.46   File "/opt/Dotfiles/dotfiles/status.py", line 59, in _wrapper
2023-09-26T13:17:10.6354287Z #23 32.46     return fun(*args, **kwargs)
2023-09-26T13:17:10.6354676Z #23 32.46   File "/opt/Dotfiles/dotfiles/os.py", line 16, in _wrapper
2023-09-26T13:17:10.6355034Z #23 32.46     ret = fun(*args, **kwargs)
2023-09-26T13:17:10.6355447Z #23 32.46   File "/opt/Dotfiles/dotfiles/package.py", line 488, in execute_install
2023-09-26T13:17:10.6355959Z #23 32.46     self._execute_steps(K_INSTALL, Stages.INSTALL, executor, transformers)
2023-09-26T13:17:10.6356449Z #23 32.46   File "/opt/Dotfiles/dotfiles/package.py", line 439, in _execute_steps
2023-09-26T13:17:10.6356850Z #23 32.46     if not executor(**step):
2023-09-26T13:17:10.6357249Z #23 32.46   File "/opt/Dotfiles/dotfiles/stages/base.py", line 80, in __call__
2023-09-26T13:17:10.6357605Z #23 32.46     ret = fn(**args)
2023-09-26T13:17:10.6358007Z #23 32.46   File "/opt/Dotfiles/dotfiles/stages/remove_mixin.py", line 68, in remove
2023-09-26T13:17:10.6358590Z #23 32.46     raise NotADirectoryError("'where' must be an existing "
2023-09-26T13:17:10.6359198Z #23 32.46 NotADirectoryError: 'where' must be an existing directory, when given.

Factor out system-wide package install to a new, optional action

Ask the user explicitly if they want to install system-wide packages. If not, do not execute the related actions. Might need a few new flags and the extension of the YAML schema. At uninstall, only uninstall the packages that execution of an install (in dotfiles) executed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.