homely.files¶
homely.files.blockinfile()¶
blockinfile()
will add a several line of text to a target file in a single block. The lines of text are surrounded by prefix
and suffix
lines so that the block can be maintained by homely over time.
blockinfile(filename, contents, where=None, *, prefix=None, suffix=None)
filename
- The name of the file to modify. If
filename
begins with a/
it will be treated as an absolute path, otherwise it is assumed to be relative to$HOME
. You can also use~
and environment variables like$HOME
directly in the filename string. contents
- A sequence of strings representing the lines of text to add to the file. The individual lines must not contain
\n
or\r
. where
- One of
None
,homely.files.WHERE_TOP
,homely.files.WHERE_BOT
orhomely.files.WHERE_ANY
. If set toNone
the behaviour ofhomely.files.WHERE_ANY
will be used. prefix=None
- A string containing a line of text which is guaranteed to be unique in the file and can be used to determine where the block starts.
suffix=None
- A string containing a line of text which is guaranteed to be unique in the file and can be used to determine where the block ends.
If prefix=None
or suffix=None
then a prefix or suffix (respectively) will be generated for you automatically. The generated line will start with #
since this represents a comment in most config file languages. If the target file is named .vimrc
or ends in .vim
, the vim comment character "
will be used instead.
block()
is idempotent and will also make sure there is only one occurrence of the prefix...suffix
block in the file, at the location specified by where
:
where=homely.files.WHERE_TOP
- The block will be added or moved to the top of the file.
where=homely.files.WHERE_BOT
- The block will be added or moved to the bottom of the file.
where=homely.files.WHERE_ANY
orwhere=None
- The block will be added to the bottom of the file, but if it is already present in the file it will be left wherever it is. If there are multiple occurrences of the block already in the file, the first will be kept and subsequent occurrences will be removed.
Examples¶
You want to include powerline config in your .tmux.conf
, but the powerline config file is in different locations depending on the host operating system. You could find the location of the powerline module programmatically and then use blockinfile() to insert the config into your .tmux.conf
using blockinfile()
:
from os.path import dirname
from homely.files import blockinfile, WHERE_TOP
from homely.system import execute
# use python to import powerline and find out where it is installed
cmd = ['python', '-c', 'import powerline; print(powerline.__file__)']
stdout = execute(cmd, stdout=True)[1]
powerline_pkg = dirname(stdout.strip().decode('utf-8'))
lines = [
'run-shell "powerline-daemon --replace -q"',
'source "{}/bindings/tmux/powerline.conf"'.format(powerline_pkg),
])
blockinfile('.tmux.conf', lines, WHERE_BOT)
Automatic Cleanup¶
If homely does modify a file using blockinfile()
, it will remember this
fact so that it can [possibly] perform automatic cleanup in the future. Each
time you run homely update homely will check to see if blockinfile()
was called with the same prefix/suffix combination, and if it wasn’t then the
block will be removed from the file. This means that you don’t need to remember
to remove the lines you aren’t using any more – simply remove the call to
blockinfile()
and homely will clean it up for you.
Note: after cleaning up a blockinfile()
section, homely will re-run all lineinfile()
and blockinfile()
functions that targetted that file. This ensures that when a block is removed from a file, it won’t accidentally remove something that was still wanted by a lineinfile()
.
See Example 4: Cleaning Modified Files for more information about this feature.
homely.files.download()¶
download()
will download a single file from a target URL.
download(url, dest, expiry=None)
url
- The URL of the file to be downloaded.
dest
- Path where the file should be downloaded to. If
dest
begins with a/
it will be treated as an absolute path, otherwise it is assumed to be relative to$HOME
. You can also use~
and environment variables like$HOME
directly in the path string. expiry
- The file will be downloaded again when the local copy is
<expiry>
seconds old. Whenexpiry=0
the file will be downloaded every time you run homely update. Whenexpiry=-1
the file will never be downloaded again. Whenexpiry=None
it will default to60*60*24*14
(2 weeks).
Examples¶
Download git completion script for bash:
from homely.files import download
url = 'https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash'
download(url, '~/src/git-completion.bash')
Automatic Cleanup¶
If homely creates the file at dest
, it will remember this fact so that it can
[possibly] perform automatic cleanup in the future. Each time you run homely
update
homely will check to see if download()
was called with the same
dest
, and if it wasn’t then the file will be removed.
See Automatic Cleanup for more information.
homely.files.lineinfile()¶
lineinfile()
will add a single line of text to a target file.
lineinfile(filename, contents, where=None)
filename
- The name of the file to modify. If
filename
begins with a/
it will be treated as an absolute path, otherwise it is assumed to be relative to$HOME
. You can also use~
and environment variables like$HOME
directly in the filename string. contents
- The line of text to add to the file.
contents
must not contain\n
or\r
. where
- One of
None
,homely.files.WHERE_TOP
,homely.files.WHERE_BOT
orhomely.files.WHERE_ANY
. If set toNone
the behaviour ofhomely.files.WHERE_ANY
will be used.
lineinfile()
is idempotent and will also make sure there is only one
occurrence of the line contents in the file, at the location specified by
where
:
where=homely.files.WHERE_TOP
- The line will be added or moved to the top of the file.
where=homely.files.WHERE_BOT
- The line will be added or moved to the bottom of the file.
where=homely.files.WHERE_ANY
orwhere=None
- The line will be added to the bottom of the file, but if it is already present in the file it will be left wherever it is. If there are multiple occurrences of the line already in the file, the first will be kept and subsequent occurrences will be removed.
Examples¶
Use lineinfile()
to add a line to the end of your .bashrc
:
from homely.files import lineinfile, WHERE_BOT
lineinfile('.bashrc', 'PATH=$HOME/dotfiles/bin:$PATH', WHERE_BOT)
Use lineinfile()
to add a line to the top of your ~/.vimrc
which
sources a shared vimrc inside your dotfiles repo:
from homely.files import lineinfile, WHERE_TOP
lineinfile('~/.vimrc', 'source $HOME/dotfiles/vimrc.vim', WHERE_TOP)
Automatic Cleanup¶
If homely does modify a file using lineinfile()
, it will remember this fact
so that it can [possibly] perform automatic cleanup in the future. Each time
you run homely update homely will check to see if lineinfile()
was
called with the same arguments, and if it wasn’t then the line will be removed
from the file. This means that you don’t need to remember to remove the lines
you aren’t using any more – simply remove the call to lineinfile()
and
homely will clean it up for you.
Note: after cleaning up line added by a lineinfile()
that is no longer present, homely will re-run all lineinfile()
and blockinfile()
functions that targetted that file. This ensures that when a line is removed from a file, it won’t accidentally remove something that was still wanted by another lineinfile()
or blockinfile()
. See Example 4: Cleaning Modified Files for more information about this feature.
homely.files.mkdir()¶
mkdir()
will create the nominated directory if it doesn’t already exist.
mkdir(path)
path
- The path to be created. If
path
begins with a/
it will be treated as an absolute path, otherwise it is assumed to be relative to$HOME
. You can also use~
and environment variables like$HOME
directly in the path string.
Examples¶
Different ways to create ~/bin
directory:
from homely.files import mkdir
# absolute path
mkdir('/home/peter/bin')
# path implicitly relative to $HOME
mkdir('bin')
# "~" expansion works
mkdir('~/bin')
# Environment variables are also expanded
mkdir('$HOME/bin')
Automatic Cleanup¶
If homely does create the directory, it will remember this fact so that it can
[possibly] perform automatic cleanup in the future. Each time you run
homely update homely will check to see if mkdir()
was called, and if
it wasn’t then the directory will be removed. This means that you don’t need to
remember to delete directories you aren’t using any more - simply remove the
call to mkdir()
and homely will clean it up for you. Note that the
directory won’t be cleaned up if it is still in use. See
Automatic Cleanup for more information.
homely.files.symlink()¶
symlink()
will create a symlink if it doesn’t already exist.
symlnk(target, linkname=None)
target
- The file or directory to symlink to. Typically this will be the name of a
file in your dotfiles repo. If
target
begins with a/
it will be treated as an absolute path, otherwise it is assumed to be relative to the current dotfiles repo. You can also use~
and environment variables like$HOME
directly in the target string. linkname
- Where to create the symlink. If this parameter is omitted, it will default
to
$HOME+basename(target)
. E.g., iftarget
was'.bashrc'
, thenlinkname
would default to'~/.bashrc'
. Iflinkname
begins with a/
it will be treated as an absolute path, otherwise it is assumed to be relative to$HOME
. You can also use~
and environment variables like$HOME
directly in the target string.
Examples¶
Create a symlink to ~/.bashrc
to [dotfiles]/shell/.bashrc
:
from homely.files import symlink
# absolute linkname
symlink('shell/.bashrc', '/home/peter/.bashrc')
# linkname implicitly relative to $HOME
symlink('shell/.bashrc', '.bashrc')
# automatic linkname=$HOME+basename(target)
symlink('shell/.bashrc')
Automatic Cleanup¶
If homely creates the symlink, it will remember this fact so that it can
[possibly] perform automatic cleanup in the future. Each time you run
homely update homely will check to see if symlink()
was called with
the same target/linkname, and if it wasn’t then the symlink will be removed.
This means that you don’t need to remember to delete symlinks you aren’t using
any more - simply remove the call to symlink()
and homely will clean it up
for you. Note that the symlink won’t be cleaned up if it has been modified
by something other than homely, or replaced with a regular file or directory.
See Automatic Cleanup for more information.
homely.files.writefile()¶
writefile()
gives you a file handle for creating or overwriting a file on disk.
writefile(filename)
filename
- The name of the file to create or overwrite. If
filename
begins with a/
it will be treated as an absolute path, otherwise it is assumed to be relative to$HOME
. You can also use~
and environment variables like$HOME
directly in the filename string.
Examples¶
Write out a config file for the Composer dependency manager for PHP.
An additional private repository will be conditionally added to the config JSON if the user answers
Y
when asked.:
import json
from homely.files import mkdir, writefile
# base config
composer_config = {
'minimum-stability': 'dev',
'prefer-stable': True,
}
# optional extra repository
if yesno('use_my_private_composer_repo', 'Use my private composer repo?'):
composer_config['repositories'] = [
{'type': 'composer', 'url': 'http://packages.example.com'}
]
# now write the JSON file
mkdir('~/.config')
mkdir('~/.config/composer')
with writefile('~/.config/composer/composer.json') as f:
json.dump(composer_config, f)
Automatic Cleanup¶
If a file doesn’t exist and Homely has to create it, then Homely will take ownership of the file and
will [possibly] perform automatic cleanup in the future. Each time you run homely update
homely
will check to see if writefile()
was used to write the same file again, and if it wasn’t then
the file will be removed.
But if the file already exists before Homely writes to it for the first time, then homely won’t take ownership of the file and won’t automatically remove it aftewards.
See Automatic Cleanup for more information.