Compare commits
10 Commits
c995f07e67
...
86fad9b83f
Author | SHA1 | Date |
---|---|---|
Lertsenem | 86fad9b83f | |
Lertsenem | d54b818a2e | |
Lertsenem | 755b079ab6 | |
Lertsenem | 671bd90024 | |
Lertsenem | 41226d0489 | |
Lertsenem | e6c4dcbdbc | |
Lertsenem | 20566a3c89 | |
Lertsenem | c6687e7b9e | |
Lertsenem | b402cba1d9 | |
Lertsenem | fbc72c0c12 |
|
@ -0,0 +1,90 @@
|
||||||
|
persoconf
|
||||||
|
=========
|
||||||
|
|
||||||
|
*persoconf* is a python script intended to keep track of all your personal
|
||||||
|
configuration files (also known as dotfiles).
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
If you want to skip this and get to the point: there's a 'help' command
|
||||||
|
available, and +--help/-h+ options for every other command.
|
||||||
|
|
||||||
|
|
||||||
|
Add an app to your persoconf repo:
|
||||||
|
|
||||||
|
----
|
||||||
|
$> persoconf add myapp
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
Add dotfiles and config directories to this app:
|
||||||
|
|
||||||
|
----
|
||||||
|
$> persoconf add myapp ~/.myapp.config
|
||||||
|
$> persoconf add myapp ~/.config/myapp/
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
List the files and dirs saved in persoconf for an app:
|
||||||
|
|
||||||
|
----
|
||||||
|
$> persoconf list -f
|
||||||
|
tmux
|
||||||
|
tmux.conf
|
||||||
|
awesome
|
||||||
|
rc.lua
|
||||||
|
vim
|
||||||
|
vimrc
|
||||||
|
myapp
|
||||||
|
myapp.config
|
||||||
|
myapp/
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
Check if modifications occured on your config files:
|
||||||
|
|
||||||
|
----
|
||||||
|
$> echo "some change in my conf" >> ~/.myapp.config
|
||||||
|
$> persoconf check
|
||||||
|
persoconf:WARNING: File ~/.myapp.config was modified
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
Update persoconf saved files with the latest configuration available:
|
||||||
|
|
||||||
|
----
|
||||||
|
$> persoconf update
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
Package your dotfiles to move them on another machine:
|
||||||
|
|
||||||
|
----
|
||||||
|
$> persoconf package --pkgtype tgz
|
||||||
|
$> ls
|
||||||
|
persoconf.20160602.tgz
|
||||||
|
$> tar tzf persoconf.20160602.tgz
|
||||||
|
.config/awesome/rc.lua
|
||||||
|
.config/myapp/somefile
|
||||||
|
.config/myapp/someotherfile
|
||||||
|
.myapp.config
|
||||||
|
.tmux.conf
|
||||||
|
.vimrc
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
Internals
|
||||||
|
---------
|
||||||
|
|
||||||
|
All persoconf data is by default saved in a '.config/persoconf' directory. You
|
||||||
|
can override this location with the global +--rootdir+ option. If the rootdir
|
||||||
|
location does not exist when you first try to use persoconf, persoconf will ask
|
||||||
|
if you want to create it.
|
||||||
|
|
||||||
|
Basically, data is saved as is (which means textfiles and dirs, mostly), and
|
||||||
|
metadata is saved as json files.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// vim: set ft=asciidoc :
|
|
@ -6,26 +6,26 @@ import os.path
|
||||||
import utils
|
import utils
|
||||||
from metafile import Metafile, MalformedMetafileError, NoPathDefinedError
|
from metafile import Metafile, MalformedMetafileError, NoPathDefinedError
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def init(parser):
|
def init(parser):
|
||||||
|
|
||||||
parser.add_argument( "app" ,
|
parser.add_argument( "app",
|
||||||
type=str ,
|
type=str,
|
||||||
help="The app to add, or the app to add a conf " \
|
help="The app to add, or the app to add a conf " \
|
||||||
"file to" )
|
"file to" )
|
||||||
|
|
||||||
parser.add_argument( "conf" ,
|
parser.add_argument( "conf",
|
||||||
nargs="?" ,
|
nargs="?",
|
||||||
type=str ,
|
type=str,
|
||||||
help="The conf file or directory to add to the app" )
|
help="The conf file or directory to add to the app" )
|
||||||
|
|
||||||
parser.add_argument( "--confname" ,
|
parser.add_argument( "--confname",
|
||||||
type=str ,
|
type=str,
|
||||||
help="A special name to save the conf " \
|
help="A special name to save the conf " \
|
||||||
"file/directory in the persoconf directory" )
|
"file/directory in the persoconf directory" )
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def run(args, persoconf, logger):
|
def run(args, persoconf, logger):
|
||||||
|
|
||||||
# Check (and create) the app directory
|
# Check (and create) the app directory
|
||||||
|
@ -51,37 +51,17 @@ def run(args, persoconf, logger):
|
||||||
if args.conf is None:
|
if args.conf is None:
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
# Check that the conf file we are saving exists
|
|
||||||
if args.confname:
|
|
||||||
confname = args.confname
|
|
||||||
else:
|
|
||||||
confname = args.conf
|
|
||||||
|
|
||||||
# We need to remove trailing '/' because 'os.path.basename("toto/")'
|
|
||||||
# returns ''. And that's not cool.
|
|
||||||
while confname[-1] == os.path.sep :
|
|
||||||
confname = confname[:-1] # Remove trailing slashes
|
|
||||||
|
|
||||||
confname = os.path.basename(confname)
|
|
||||||
|
|
||||||
# Remove leading dots, so the name under which the conffile is saved is
|
|
||||||
# not hidden.
|
|
||||||
while confname[0] == ".":
|
|
||||||
confname = confname[1:] # Remove leading dots
|
|
||||||
|
|
||||||
confpath = appdir + "/" + confname
|
|
||||||
|
|
||||||
# Load app META file
|
# Load app META file
|
||||||
try:
|
try:
|
||||||
appmeta = Metafile( json_path = os.path.join( appdir ,
|
appmeta = Metafile( json_path = os.path.join( appdir,
|
||||||
persoconf.metafile ) )
|
persoconf.metafile ) )
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.info( "Metafile %s does not exist for app %s"
|
logger.info( "Metafile %s does not exist for app %s"
|
||||||
% (persoconf.metafile, args.app) )
|
% (persoconf.metafile, args.app) )
|
||||||
appmeta = Metafile( name=args.app )
|
appmeta = Metafile( name=args.app )
|
||||||
appmeta.json_path = os.path.join( persoconf.path ,
|
appmeta.json_path = os.path.join( persoconf.path,
|
||||||
args.app ,
|
args.app,
|
||||||
persoconf.metafile )
|
persoconf.metafile )
|
||||||
|
|
||||||
except MalformedMetafileError:
|
except MalformedMetafileError:
|
||||||
|
@ -107,9 +87,54 @@ def run(args, persoconf, logger):
|
||||||
% (absconf, dstdic[absconf], args.app) )
|
% (absconf, dstdic[absconf], args.app) )
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
# Check that the conf file we are saving exists
|
||||||
|
if args.confname:
|
||||||
|
confname = args.confname
|
||||||
|
else:
|
||||||
|
confname = args.conf
|
||||||
|
|
||||||
|
# We need to remove trailing '/' because 'os.path.basename("toto/")'
|
||||||
|
# returns ''. And that's not cool.
|
||||||
|
while confname[-1] == os.path.sep :
|
||||||
|
confname = confname[:-1] # Remove trailing slashes
|
||||||
|
|
||||||
|
confname = os.path.basename(confname)
|
||||||
|
|
||||||
|
# Remove leading dots, so the name under which the conffile is saved is
|
||||||
|
# not hidden.
|
||||||
|
while confname[0] == ".":
|
||||||
|
confname = confname[1:] # Remove leading dots
|
||||||
|
|
||||||
|
|
||||||
|
# Check the conf file name
|
||||||
|
if ( confname == persoconf.metafile
|
||||||
|
or confname in appmeta.files ):
|
||||||
|
|
||||||
|
# If the confanme was user-defined, it's a serious error.
|
||||||
|
if args.confname:
|
||||||
|
logger.error( "Confname '%s' is already taken: try another one"
|
||||||
|
% confname )
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
# Otherwise it's cool, we just have to change the confname by ourselves
|
||||||
|
logger.info( "Confname '%s' is already taken: trying another one"
|
||||||
|
% confname )
|
||||||
|
|
||||||
|
ending = 1
|
||||||
|
|
||||||
|
while ( confname + "." + str(ending) == persoconf.metafile
|
||||||
|
or confname + "." + str(ending) in appmeta.files ):
|
||||||
|
ending += 1
|
||||||
|
|
||||||
|
confname = confname + "." + str(ending)
|
||||||
|
logger.info( "New confname is '%s'" % confname )
|
||||||
|
|
||||||
|
# Deduce the path from the conf file name
|
||||||
|
confpath = appdir + "/" + confname
|
||||||
|
|
||||||
# Copy the file (or directory)
|
# Copy the file (or directory)
|
||||||
if utils.copy_file_or_directory( logger ,
|
if utils.copy_file_or_directory( logger,
|
||||||
path_dst=confpath ,
|
path_dst=confpath,
|
||||||
path_src=args.conf,
|
path_src=args.conf,
|
||||||
overwrite=False ):
|
overwrite=False ):
|
||||||
logger.info( "New conf file or directory '%s' associated with app '%s'"
|
logger.info( "New conf file or directory '%s' associated with app '%s'"
|
||||||
|
@ -132,3 +157,5 @@ def run(args, persoconf, logger):
|
||||||
"defined"
|
"defined"
|
||||||
% appmeta.name )
|
% appmeta.name )
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
# TODO Add or update the app METAFILE in a 'persoconf' special app.
|
|
@ -1,38 +1,44 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import os.path
|
import os, os.path
|
||||||
import filecmp
|
import filecmp
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from metafile import Metafile, MalformedMetafileError
|
from metafile import Metafile, MalformedMetafileError
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def init(parser):
|
def init(parser):
|
||||||
"""Initialize check subcommand"""
|
"""Initialize check subcommand"""
|
||||||
|
|
||||||
parser.add_argument( "app" ,
|
parser.add_argument( "app",
|
||||||
type=str ,
|
type=str,
|
||||||
nargs="?" ,
|
nargs="?",
|
||||||
help="The app to check" )
|
help="The app to check" )
|
||||||
|
|
||||||
parser.add_argument( "files" ,
|
parser.add_argument( "files",
|
||||||
type=str ,
|
type=str,
|
||||||
nargs="*" ,
|
nargs="*",
|
||||||
default=[] ,
|
default=[],
|
||||||
help="The files to check ; default to all " \
|
help="The files to check ; default to all " \
|
||||||
"added files" )
|
"added files" )
|
||||||
|
|
||||||
parser.add_argument( "-d", "--diff" ,
|
parser.add_argument( "-d", "--diff",
|
||||||
type=str ,
|
action="store_true",
|
||||||
help="Print the diff between the saved and the new " \
|
help="Print the diff between the saved and the new " \
|
||||||
"file/directory" )
|
"files" )
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def run(args, persoconf, logger):
|
def run(args, persoconf, logger):
|
||||||
|
|
||||||
logger.debug("Starting 'check' command")
|
logger.debug("Starting 'check' command")
|
||||||
|
|
||||||
|
difftool = None
|
||||||
|
if args.diff:
|
||||||
|
difftool = os.environ.get('DIFFTOOL', 'vimdiff')
|
||||||
|
logger.info("Selecting %s as diff tool" % difftool)
|
||||||
|
|
||||||
# app == None => check all apps
|
# app == None => check all apps
|
||||||
apps_to_check = {}
|
apps_to_check = {}
|
||||||
if args.app is None:
|
if args.app is None:
|
||||||
|
@ -84,7 +90,8 @@ def run(args, persoconf, logger):
|
||||||
|
|
||||||
_compare_and_log( original_file_path,
|
_compare_and_log( original_file_path,
|
||||||
persoconf_backup_path,
|
persoconf_backup_path,
|
||||||
logger )
|
logger,
|
||||||
|
difftool )
|
||||||
|
|
||||||
# 2) If not, it must be a real filename
|
# 2) If not, it must be a real filename
|
||||||
else:
|
else:
|
||||||
|
@ -101,7 +108,8 @@ def run(args, persoconf, logger):
|
||||||
|
|
||||||
_compare_and_log( original_file_path,
|
_compare_and_log( original_file_path,
|
||||||
persoconf_backup_path,
|
persoconf_backup_path,
|
||||||
logger )
|
logger,
|
||||||
|
difftool )
|
||||||
|
|
||||||
|
|
||||||
# 3) Otherwise, no idea what it is
|
# 3) Otherwise, no idea what it is
|
||||||
|
@ -125,11 +133,15 @@ def run(args, persoconf, logger):
|
||||||
|
|
||||||
_compare_and_log( original_file_path,
|
_compare_and_log( original_file_path,
|
||||||
persoconf_backup_path,
|
persoconf_backup_path,
|
||||||
logger )
|
logger,
|
||||||
|
difftool )
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def _compare_and_log(original_file_path, persoconf_backup_path, logger):
|
def _compare_and_log( original_file_path,
|
||||||
|
persoconf_backup_path,
|
||||||
|
logger,
|
||||||
|
difftool = None ):
|
||||||
"""Compare a file with its persoconf backup and log the result (at info
|
"""Compare a file with its persoconf backup and log the result (at info
|
||||||
level if the files are matching, warning level if they are not)."""
|
level if the files are matching, warning level if they are not)."""
|
||||||
|
|
||||||
|
@ -158,6 +170,8 @@ def _compare_and_log(original_file_path, persoconf_backup_path, logger):
|
||||||
else:
|
else:
|
||||||
logger.warning( "File %s was modified"
|
logger.warning( "File %s was modified"
|
||||||
% original_file_path )
|
% original_file_path )
|
||||||
|
if difftool:
|
||||||
|
subprocess.call([ difftool, resolved_pbp, resolved_ofp ])
|
||||||
|
|
||||||
except FileNotFoundError as err:
|
except FileNotFoundError as err:
|
||||||
if err.filename == resolved_pbp:
|
if err.filename == resolved_pbp:
|
|
@ -9,32 +9,32 @@ import utils
|
||||||
from metafile import Metafile, MalformedMetafileError
|
from metafile import Metafile, MalformedMetafileError
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def init(parser):
|
def init(parser):
|
||||||
parser.add_argument( "app" ,
|
parser.add_argument( "app",
|
||||||
type=str ,
|
type=str,
|
||||||
help="The app to delete, or the app to delete a " \
|
help="The app to delete, or the app to delete a " \
|
||||||
"conf file from" )
|
"conf file from" )
|
||||||
|
|
||||||
parser.add_argument( "files" ,
|
parser.add_argument( "files",
|
||||||
nargs="*" ,
|
nargs="*",
|
||||||
type=str ,
|
type=str,
|
||||||
help="The conf files or directories to delete from " \
|
help="The conf files or directories to delete from " \
|
||||||
"the app" )
|
"the app" )
|
||||||
|
|
||||||
parser.add_argument( "--force-yes", "-y" ,
|
parser.add_argument( "--force-yes", "-y",
|
||||||
action="store_true" ,
|
action="store_true",
|
||||||
help="Don't ask silly questions" )
|
help="Don't ask silly questions" )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def run(args, persoconf, logger):
|
def run(args, persoconf, logger):
|
||||||
|
|
||||||
# Does this app really exists ?
|
# Does this app really exists ?
|
||||||
try:
|
try:
|
||||||
appmeta = Metafile( json_path = os.path.join( persoconf.path ,
|
appmeta = Metafile( json_path = os.path.join( persoconf.path,
|
||||||
args.app ,
|
args.app,
|
||||||
persoconf.metafile ) )
|
persoconf.metafile ) )
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.error( "App %s does not seem to exist" % args.app )
|
logger.error( "App %s does not seem to exist" % args.app )
|
||||||
|
@ -80,9 +80,9 @@ def run(args, persoconf, logger):
|
||||||
# 1) It's probably a confname
|
# 1) It's probably a confname
|
||||||
if f in appmeta.files:
|
if f in appmeta.files:
|
||||||
if utils.delete_file_or_dir(
|
if utils.delete_file_or_dir(
|
||||||
logger = logger ,
|
logger = logger,
|
||||||
path = os.path.join(persoconf.path,
|
path = os.path.join(persoconf.path,
|
||||||
appmeta.name ,
|
appmeta.name,
|
||||||
f )
|
f )
|
||||||
):
|
):
|
||||||
# File deleted, let's delete the entry in Metafile
|
# File deleted, let's delete the entry in Metafile
|
||||||
|
@ -104,7 +104,7 @@ def run(args, persoconf, logger):
|
||||||
if delete_file_or_dir( logger = logger,
|
if delete_file_or_dir( logger = logger,
|
||||||
path = os.path.join(
|
path = os.path.join(
|
||||||
persoconf.path,
|
persoconf.path,
|
||||||
appmeta.name ,
|
appmeta.name,
|
||||||
dstdir[absf]
|
dstdir[absf]
|
||||||
)
|
)
|
||||||
):
|
):
|
|
@ -3,24 +3,24 @@
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def init(parser):
|
def init(parser):
|
||||||
parser.add_argument( "apps" ,
|
parser.add_argument( "apps",
|
||||||
type=str ,
|
type=str,
|
||||||
nargs="*" ,
|
nargs="*",
|
||||||
default=[] ,
|
default=[],
|
||||||
help="The apps to list ; defaults to all " \
|
help="The apps to list ; defaults to all " \
|
||||||
"apps" )
|
"apps" )
|
||||||
|
|
||||||
parser.add_argument( "--show-files", "-f" ,
|
parser.add_argument( "--show-files", "-f",
|
||||||
action="store_true" ,
|
action="store_true",
|
||||||
help="Show the files for each app ; it is " \
|
help="Show the files for each app ; it is " \
|
||||||
"automatically set if you specify the " \
|
"automatically set if you specify the " \
|
||||||
"apps to list." )
|
"apps to list." )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def run(args, persoconf, logger):
|
def run(args, persoconf, logger):
|
||||||
|
|
||||||
app_list = persoconf.list_apps(logger=logger)
|
app_list = persoconf.list_apps(logger=logger)
|
|
@ -0,0 +1,145 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import time
|
||||||
|
import tarfile
|
||||||
|
|
||||||
|
import utils
|
||||||
|
|
||||||
|
from metafile import Metafile, MalformedMetafileError
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
def init(parser):
|
||||||
|
|
||||||
|
parser.add_argument( "apps",
|
||||||
|
type=str,
|
||||||
|
nargs="*",
|
||||||
|
default=[],
|
||||||
|
help="The apps to package ; defaults to all " \
|
||||||
|
"apps" )
|
||||||
|
|
||||||
|
parser.add_argument( "--pkgtype", "-t",
|
||||||
|
type=str,
|
||||||
|
nargs="?",
|
||||||
|
default="tgz",
|
||||||
|
choices = [ "tgz" ],
|
||||||
|
help="The type of package to use" )
|
||||||
|
|
||||||
|
parser.add_argument( "--pkgname", "-p",
|
||||||
|
type=str,
|
||||||
|
nargs="?",
|
||||||
|
default="persoconf." + (time.strftime("%Y%m%d")),
|
||||||
|
help="The name of the package to create" )
|
||||||
|
|
||||||
|
parser.add_argument( "--nopersoconf", "-n",
|
||||||
|
action="store_true",
|
||||||
|
help="Do not include persoconf own config " \
|
||||||
|
"directory in the resulting package" )
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
def run(args, persoconf, logger):
|
||||||
|
|
||||||
|
pkgname = args.pkgname
|
||||||
|
|
||||||
|
# If no app is given: package all apps
|
||||||
|
if args.apps == []:
|
||||||
|
logger.info("Packaging all apps")
|
||||||
|
args.apps = persoconf.list_apps(logger=logger)
|
||||||
|
|
||||||
|
# Some apps were specified, so we list them with their files
|
||||||
|
appmetas = []
|
||||||
|
for app in args.apps :
|
||||||
|
# Load app META file
|
||||||
|
try:
|
||||||
|
appmetas.append(
|
||||||
|
Metafile(
|
||||||
|
json_path = os.path.join(
|
||||||
|
persoconf.path,
|
||||||
|
app,
|
||||||
|
persoconf.metafile
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
logger.warning( "Metafile %s does not exist for app %s; ignoring"
|
||||||
|
% (persoconf.metafile, app) )
|
||||||
|
continue
|
||||||
|
|
||||||
|
except MalformedMetafileError:
|
||||||
|
logger.warning( "Malformed metafile %s in app %s; ignoring"
|
||||||
|
% (persoconf.metafile, app) )
|
||||||
|
continue
|
||||||
|
|
||||||
|
# TODO check that the app exists
|
||||||
|
|
||||||
|
# Adds the app name if there is only one packaged
|
||||||
|
if len(appmetas) == 1:
|
||||||
|
pkgname += ("." + appmetas[0].name)
|
||||||
|
|
||||||
|
# Switch according to the pkgtype
|
||||||
|
if args.pkgtype == "tgz":
|
||||||
|
|
||||||
|
pkgname += ".tgz"
|
||||||
|
|
||||||
|
# Create a tar containing the files in the right place
|
||||||
|
pkg = tarfile.open(pkgname, "w:gz")
|
||||||
|
|
||||||
|
for appmeta in appmetas:
|
||||||
|
|
||||||
|
# Add META file to the archive
|
||||||
|
if not args.nopersoconf:
|
||||||
|
filename_meta = os.path.join( persoconf.path,
|
||||||
|
appmeta.name,
|
||||||
|
persoconf.metafile )
|
||||||
|
filedest_meta = utils.contractuser( filename_meta )
|
||||||
|
|
||||||
|
if filedest_meta.startswith("~/"):
|
||||||
|
filedest_meta = filedest_meta[2:]
|
||||||
|
|
||||||
|
try:
|
||||||
|
pkg.add(filename_meta, arcname=filedest_meta)
|
||||||
|
logger.info(
|
||||||
|
"Adding app %s to package".format(appmeta.name)
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(
|
||||||
|
"Failed to add app {app} to tar package {pkg}: {err}" \
|
||||||
|
.format( app = appmeta.name,
|
||||||
|
pkg = pkgname,
|
||||||
|
err = str(e) )
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
for f in appmeta.files:
|
||||||
|
filename = os.path.join( persoconf.path,
|
||||||
|
appmeta.name,
|
||||||
|
f )
|
||||||
|
filedest = appmeta.files[f]["dest"]
|
||||||
|
filedest_pc = utils.contractuser( filename )
|
||||||
|
|
||||||
|
# Remove possible 'home'. The final targz should be extracted
|
||||||
|
# at $HOME.
|
||||||
|
if filedest.startswith("~/"):
|
||||||
|
filedest = filedest[2:]
|
||||||
|
if filedest_pc.startswith("~/"):
|
||||||
|
filedest_pc = filedest_pc[2:]
|
||||||
|
|
||||||
|
# TODO save and restore owners and permissions
|
||||||
|
try:
|
||||||
|
pkg.add(filename, arcname=filedest)
|
||||||
|
|
||||||
|
if not args.nopersoconf:
|
||||||
|
pkg.add(filename, arcname=filedest_pc)
|
||||||
|
|
||||||
|
logger.info("Adding %s to package" % f)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning( "Failed to add %s to tar package %s: %s"
|
||||||
|
% (f, pkgname, str(e)) )
|
||||||
|
|
||||||
|
|
||||||
|
pkg.close()
|
||||||
|
|
|
@ -6,22 +6,22 @@ import os.path
|
||||||
import utils
|
import utils
|
||||||
from metafile import Metafile, MalformedMetafileError
|
from metafile import Metafile, MalformedMetafileError
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def init(parser):
|
def init(parser):
|
||||||
|
|
||||||
parser.add_argument( "app" ,
|
parser.add_argument( "app",
|
||||||
type=str ,
|
type=str,
|
||||||
nargs="?" ,
|
nargs="?",
|
||||||
help="The app to update" )
|
help="The app to update" )
|
||||||
|
|
||||||
parser.add_argument( "files" ,
|
parser.add_argument( "files",
|
||||||
type=str ,
|
type=str,
|
||||||
nargs="*" ,
|
nargs="*",
|
||||||
default=[] ,
|
default=[],
|
||||||
help="The files to update ; default to all " \
|
help="The files to update ; default to all " \
|
||||||
"added files" )
|
"added files" )
|
||||||
|
|
||||||
# --------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
def run(args, persoconf, logger):
|
def run(args, persoconf, logger):
|
||||||
|
|
||||||
# app == None => update all apps
|
# app == None => update all apps
|
||||||
|
@ -32,8 +32,8 @@ def run(args, persoconf, logger):
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
appmeta = Metafile(
|
appmeta = Metafile(
|
||||||
json_path = os.path.join( persoconf.path ,
|
json_path = os.path.join( persoconf.path,
|
||||||
args.app ,
|
args.app,
|
||||||
persoconf.metafile )
|
persoconf.metafile )
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -66,10 +66,10 @@ def run(args, persoconf, logger):
|
||||||
if f in apps_to_update[app].files:
|
if f in apps_to_update[app].files:
|
||||||
|
|
||||||
if utils.copy_file_or_directory(
|
if utils.copy_file_or_directory(
|
||||||
logger ,
|
logger,
|
||||||
path_dst = os.path.join( persoconf.path,
|
path_dst = os.path.join( persoconf.path,
|
||||||
app ,
|
app,
|
||||||
f ) ,
|
f ),
|
||||||
path_src = apps_to_update[app].files[f]["dest"]
|
path_src = apps_to_update[app].files[f]["dest"]
|
||||||
):
|
):
|
||||||
|
|
||||||
|
@ -93,10 +93,10 @@ def run(args, persoconf, logger):
|
||||||
if absf in dstdic:
|
if absf in dstdic:
|
||||||
|
|
||||||
if utils.copy_file_or_directory(
|
if utils.copy_file_or_directory(
|
||||||
logger ,
|
logger,
|
||||||
path_dst = os.path.join( persoconf.path,
|
path_dst = os.path.join( persoconf.path,
|
||||||
app ,
|
app,
|
||||||
dstdic[absf] ) ,
|
dstdic[absf] ),
|
||||||
path_src = absf
|
path_src = absf
|
||||||
):
|
):
|
||||||
logger.info( "Updated %s from %s"
|
logger.info( "Updated %s from %s"
|
||||||
|
@ -121,10 +121,10 @@ def run(args, persoconf, logger):
|
||||||
|
|
||||||
for f in apps_to_update[app].files:
|
for f in apps_to_update[app].files:
|
||||||
if utils.copy_file_or_directory(
|
if utils.copy_file_or_directory(
|
||||||
logger ,
|
logger,
|
||||||
path_dst = os.path.join( persoconf.path,
|
path_dst = os.path.join( persoconf.path,
|
||||||
app ,
|
app,
|
||||||
f ) ,
|
f ),
|
||||||
path_src = apps_to_update[app].files[f]["dest"]
|
path_src = apps_to_update[app].files[f]["dest"]
|
||||||
):
|
):
|
||||||
logger.info( "Updated %s from %s"
|
logger.info( "Updated %s from %s"
|
||||||
|
@ -132,7 +132,7 @@ def run(args, persoconf, logger):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warning( "Failed to update %s from %s ; ignoring"
|
logger.warning( "Failed to update %s from %s ; ignoring"
|
||||||
% ( f ,
|
% ( f,
|
||||||
apps_to_update[app].files[f]["dest"] )
|
apps_to_update[app].files[f]["dest"] )
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,77 +21,86 @@ import commands.list, commands.package, commands.update, commands.add, \
|
||||||
|
|
||||||
|
|
||||||
# ARGPARSE
|
# ARGPARSE
|
||||||
########################################
|
##############################################################################
|
||||||
# Argument parsing using argparse
|
# Argument parsing using argparse
|
||||||
|
# =============================================================================
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
parser.add_argument( "--rootdir" ,
|
parser.add_argument( "--rootdir",
|
||||||
type=str ,
|
type=str,
|
||||||
default="~/.config/persoconf/" ,
|
default="~/.config/persoconf/",
|
||||||
help="The persoconf directory to use" )
|
help="The persoconf directory to use" )
|
||||||
|
|
||||||
parser.add_argument( "--metafile" ,
|
parser.add_argument( "--metafile",
|
||||||
type=str ,
|
type=str,
|
||||||
default="META" ,
|
default="META",
|
||||||
help="The name of the metadata files" )
|
help="The name of the metadata files" )
|
||||||
|
|
||||||
parser.add_argument( "--verbose", "-v" ,
|
parser.add_argument( "--verbose", "-v",
|
||||||
action="store_true" ,
|
action="store_true",
|
||||||
help="Spout out more logs" )
|
help="Spout out more logs" )
|
||||||
|
|
||||||
|
|
||||||
subparsers = parser.add_subparsers( dest="command" ,
|
subparsers = parser.add_subparsers( dest="command",
|
||||||
title="commands" )
|
title="commands" )
|
||||||
|
|
||||||
# Help
|
# Help
|
||||||
parser_help = subparsers.add_parser( "help" ,
|
# -----------------------------------------------------------------------------
|
||||||
|
parser_help = subparsers.add_parser( "help",
|
||||||
help="Print this help" )
|
help="Print this help" )
|
||||||
|
|
||||||
# List
|
# List
|
||||||
parser_list = subparsers.add_parser( "list" ,
|
# -----------------------------------------------------------------------------
|
||||||
|
parser_list = subparsers.add_parser( "list",
|
||||||
help="List backuped apps" )
|
help="List backuped apps" )
|
||||||
commands.list.init(parser_list)
|
commands.list.init(parser_list)
|
||||||
|
|
||||||
# Package
|
# Package
|
||||||
parser_package = subparsers.add_parser( "package" ,
|
# -----------------------------------------------------------------------------
|
||||||
|
parser_package = subparsers.add_parser( "package",
|
||||||
help="Package a persoconf repository" )
|
help="Package a persoconf repository" )
|
||||||
commands.package.init(parser_package)
|
commands.package.init(parser_package)
|
||||||
|
|
||||||
# Update
|
# Update
|
||||||
parser_update = subparsers.add_parser( "update" ,
|
# -----------------------------------------------------------------------------
|
||||||
|
parser_update = subparsers.add_parser( "update",
|
||||||
help="Backup an app configuration in " \
|
help="Backup an app configuration in " \
|
||||||
"the persoconf directory with " \
|
"the persoconf directory with " \
|
||||||
"the configuration in use now" )
|
"the configuration in use now" )
|
||||||
commands.update.init(parser_update)
|
commands.update.init(parser_update)
|
||||||
|
|
||||||
# Add
|
# Add
|
||||||
parser_add = subparsers.add_parser( "add" ,
|
# -----------------------------------------------------------------------------
|
||||||
|
parser_add = subparsers.add_parser( "add",
|
||||||
help="Add an app to the persoconf " \
|
help="Add an app to the persoconf " \
|
||||||
"directory, or add a config file " \
|
"directory, or add a config file " \
|
||||||
"to an existing app" )
|
"to an existing app" )
|
||||||
commands.add.init(parser_add)
|
commands.add.init(parser_add)
|
||||||
|
|
||||||
# Check
|
# Check
|
||||||
parser_check = subparsers.add_parser( "check" ,
|
# -----------------------------------------------------------------------------
|
||||||
|
parser_check = subparsers.add_parser( "check",
|
||||||
help="Checks if the backuped and the " \
|
help="Checks if the backuped and the " \
|
||||||
"original file are different." )
|
"original file are different." )
|
||||||
commands.check.init(parser_check)
|
commands.check.init(parser_check)
|
||||||
|
|
||||||
# Delete
|
# Delete
|
||||||
parser_del = subparsers.add_parser( "delete" ,
|
# -----------------------------------------------------------------------------
|
||||||
|
parser_del = subparsers.add_parser( "delete",
|
||||||
help="Delete an app from the persoconf " \
|
help="Delete an app from the persoconf " \
|
||||||
"directory, or a config file from " \
|
"directory, or a config file from " \
|
||||||
"an existing app" )
|
"an existing app" )
|
||||||
commands.delete.init(parser_del)
|
commands.delete.init(parser_del)
|
||||||
|
|
||||||
# Parse arguments
|
# Parse arguments
|
||||||
|
# =============================================================================
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Transform paths
|
# Transform paths
|
||||||
args.rootdir = os.path.expanduser(args.rootdir)
|
args.rootdir = os.path.expanduser(args.rootdir)
|
||||||
|
|
||||||
# LOGGING
|
# LOGGING
|
||||||
########################################
|
##############################################################################
|
||||||
log = logging.getLogger("persoconf")
|
log = logging.getLogger("persoconf")
|
||||||
log.setLevel(logging.DEBUG)
|
log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
@ -110,13 +119,14 @@ log_handler_console.setFormatter(log_formatter_console)
|
||||||
log.addHandler(log_handler_console)
|
log.addHandler(log_handler_console)
|
||||||
|
|
||||||
# SCRIPT
|
# SCRIPT
|
||||||
########################################
|
##############################################################################
|
||||||
# If we were asked for help, let's give some
|
# If we were asked for help, let's give some
|
||||||
if args.command in [ "help", None ]:
|
if args.command in [ "help", None ]:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
# Try to create the Persoconf
|
# Try to create the Persoconf
|
||||||
|
# =============================================================================
|
||||||
try:
|
try:
|
||||||
persoconf = Persoconf(path=args.rootdir, metafile=args.metafile)
|
persoconf = Persoconf(path=args.rootdir, metafile=args.metafile)
|
||||||
|
|
||||||
|
@ -151,38 +161,31 @@ except PersoconfRootDoesNotExistError:
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
# LIST COMMAND
|
# LIST COMMAND
|
||||||
########################################
|
# =============================================================================
|
||||||
if args.command == "list":
|
if args.command == "list":
|
||||||
commands.list.run(args, persoconf, log)
|
commands.list.run(args, persoconf, log)
|
||||||
|
|
||||||
# DELETE COMMAND
|
# DELETE COMMAND
|
||||||
########################################
|
# =============================================================================
|
||||||
if args.command == "delete":
|
if args.command == "delete":
|
||||||
commands.delete.run(args, persoconf, log)
|
commands.delete.run(args, persoconf, log)
|
||||||
|
|
||||||
# ADD COMMAND
|
# ADD COMMAND
|
||||||
########################################
|
# =============================================================================
|
||||||
if args.command == "add":
|
if args.command == "add":
|
||||||
commands.add.run(args, persoconf, log)
|
commands.add.run(args, persoconf, log)
|
||||||
|
|
||||||
# CHECK COMMAND
|
# CHECK COMMAND
|
||||||
########################################
|
# =============================================================================
|
||||||
if args.command == "check":
|
if args.command == "check":
|
||||||
commands.check.run(args, persoconf, log)
|
commands.check.run(args, persoconf, log)
|
||||||
|
|
||||||
# UPDATE COMMAND
|
# UPDATE COMMAND
|
||||||
########################################
|
# =============================================================================
|
||||||
if args.command == "update":
|
if args.command == "update":
|
||||||
commands.update.run(args, persoconf, log)
|
commands.update.run(args, persoconf, log)
|
||||||
|
|
||||||
# PACKAGE COMMAND
|
# PACKAGE COMMAND
|
||||||
########################################
|
# =============================================================================
|
||||||
if args.command == "package":
|
if args.command == "package":
|
||||||
commands.package.run(args, persoconf, log)
|
commands.package.run(args, persoconf, log)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########################################
|
|
|
@ -1,101 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import os.path
|
|
||||||
import time
|
|
||||||
import tarfile
|
|
||||||
|
|
||||||
from metafile import Metafile, MalformedMetafileError
|
|
||||||
|
|
||||||
# --------------------------------------
|
|
||||||
def init(parser):
|
|
||||||
|
|
||||||
parser.add_argument( "apps" ,
|
|
||||||
type=str ,
|
|
||||||
nargs="*" ,
|
|
||||||
default=[] ,
|
|
||||||
help="The apps to package ; defaults to all " \
|
|
||||||
"apps" )
|
|
||||||
|
|
||||||
parser.add_argument( "--pkgtype", "-t" ,
|
|
||||||
type=str ,
|
|
||||||
nargs="?" ,
|
|
||||||
default="tgz" ,
|
|
||||||
choices = [ "tgz" ] ,
|
|
||||||
help="The type of package to use" )
|
|
||||||
|
|
||||||
parser.add_argument( "--pkgname", "-p" ,
|
|
||||||
type=str ,
|
|
||||||
nargs="?" ,
|
|
||||||
default="persoconf." + (time.strftime("%Y%m%d")) ,
|
|
||||||
help="The name of the package to create" )
|
|
||||||
|
|
||||||
# --------------------------------------
|
|
||||||
def run(args, persoconf, logger):
|
|
||||||
|
|
||||||
pkgname = args.pkgname
|
|
||||||
|
|
||||||
# If no app is given: package all apps
|
|
||||||
if args.apps == []:
|
|
||||||
logger.info("Packaging all apps")
|
|
||||||
args.apps = persoconf.list_apps(logger=logger)
|
|
||||||
|
|
||||||
# Some apps were specified, so we list them with their files
|
|
||||||
appmetas = []
|
|
||||||
for app in args.apps :
|
|
||||||
# Load app META file
|
|
||||||
try:
|
|
||||||
appmetas.append(
|
|
||||||
Metafile(json_path = os.path.join(
|
|
||||||
persoconf.path ,
|
|
||||||
app ,
|
|
||||||
persoconf.metafile)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
|
||||||
logger.warning( "Metafile %s does not exist for app %s; ignoring"
|
|
||||||
% (persoconf.metafile, app) )
|
|
||||||
continue
|
|
||||||
|
|
||||||
except MalformedMetafileError:
|
|
||||||
logger.warning( "Malformed metafile %s in app %s; ignoring"
|
|
||||||
% (persoconf.metafile, app) )
|
|
||||||
continue
|
|
||||||
|
|
||||||
# TODO check that the app exists
|
|
||||||
|
|
||||||
# Adds the app name if there is only one packaged
|
|
||||||
if len(appmetas) == 1:
|
|
||||||
pkgname += ("." + appmetas[0].name)
|
|
||||||
|
|
||||||
# Switch according to the pkgtype
|
|
||||||
if args.pkgtype == "tgz":
|
|
||||||
|
|
||||||
pkgname += ".tgz"
|
|
||||||
|
|
||||||
# Create a tar containing the files in the right place
|
|
||||||
pkg = tarfile.open(pkgname, "w:gz")
|
|
||||||
|
|
||||||
for appmeta in appmetas:
|
|
||||||
for f in appmeta.files:
|
|
||||||
filename = persoconf.path +"/"+ appmeta.name +"/"+ f
|
|
||||||
filedest = appmeta.files[f]["dest"]
|
|
||||||
|
|
||||||
# Remove possible 'home'. The final targz should be extracted
|
|
||||||
# at $HOME.
|
|
||||||
if filedest.startswith("~/"):
|
|
||||||
filedest = filedest[2:]
|
|
||||||
|
|
||||||
# TODO save and restore owners and permissions
|
|
||||||
try:
|
|
||||||
pkg.add(filename, arcname=filedest)
|
|
||||||
logger.info("Adding %s to package" % f)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning( "Failed to add %s to tar package %s: %s"
|
|
||||||
% (f, pkgname, str(e)) )
|
|
||||||
|
|
||||||
|
|
||||||
pkg.close()
|
|
||||||
|
|
Loading…
Reference in New Issue