How to [tar and] compress marked files in Emacs - emacs

In dired+ in Emacs 23.2.1 on a Debian Squeeze variant I selected four files with * and then pressed Z to compress them. I answered y to the prompt and saw some status updates in the mini-buffer. Where do I find the compressed file? I tested on one file (C-u Z) and Emacs ran gzip on the one file and made it a .gz file. How do I [tar and] compress marked files in Emacs?
(To preempt any philosophical or methodological discussions about tar, gzip, other formats and archives in general, all I want is the four files to be stored in one file as compressed data. If that can be achieved via tar and gzip or compressing each directly into an archive doesn't matter.)

If dired+ is anything like dired, you can mark the files with m and then hit ! (to run a shell command on the marked files) and specify the command as tar -czf foo.tar.gz * (the * is a special marker that is replaced by the names of the marked files).

You can also archive files just by marking and copying them to an archive file.
For example, mark several files in dired, and select m-x dired-do-copy.
When prompted for destination, type test.zip. The files will be added to the zip archive automatically.
You can also uncompress files by selecting them in dired and running the command dired-do-extract
To set this up, look at the following variables:
dired-to-archive-copy-alist
dired-extract-alist
Here's my setup, which has served me for many years...
;; dired-a provides support functions, including archiving, for dired
(load "dired-a")
;; Alist with information how to add files to an archive (from dired-a)
;; Each element has the form (REGEXP ADD-CMD NEW-CMD). If REGEXP matches
;; the file name of a target, that target is an archive and ADD-CMD is a command
;; that adds to an existing archive and NEW-CMD is a command that makes a new
;; archive (overwriting an old one if it exists). ADD-CMD and NEW-CMD are:
;; 1. Nil (meaning we cannot do this for this type of archive) (one of
;; ADD-CMD and NEW-CMD must be non-nil).
;; 2. A symbol that must be a function e.g. dired-do-archive-op.
;; 3. A format string with two arguments, the source files concatenated into
;; a space separated string and the target archive.
;; 4. A list of strings, the command and its flags, to which the target and
;; the source-files are concatenated."
(setq dired-to-archive-copy-alist
'(("\\.sh\\(ar\\|[0-9]\\)*$" nil "shar %s > %s")
("\\.jar$" ("jar" "uvf") ("jar" "cvf"))
("\\.tar$" ("tar" "-uf") ("tar" "-cf"))
("\\.tgz$\\|\\.tar\\.g?[zZ]$" ("tar" "-uf %s" "|" "gzip > %s") ("tar" "-czvf"))
("\\.ear$" ("zip" "-qr") ("zip" "-qr"))
; ("\\.rar$" ("rar" "a") ("rar" "a"))
("\\.war$" ("zip" "-qr") ("zip" "-qr"))
("\\.zip$" ("zip" "-qr") ("zip" "-qr"))
("\\.wmz$" ("zip" "-qr") ("zip" "-qr")) ;; for media player skins
("\\.arc$" ("arc" "a") nil)
("\\.zoo$" ("zoo" "aP") nil)
))
;; use pkzip with manipulating zip files (t) from within dired (use zip
;; and unzip otherwise)
(setq archive-zip-use-pkzip nil)
;; add these file types to archive mode to allow viewing and changing
;; their contents
(add-to-list 'auto-mode-alist '("\\.[ejrw]ar$\\'" . archive-mode))
;; modify the dired-extract switches to use the directory
;; ~/download/tryout as the default extract directory for zip files
(defconst MY_TRYOUT_DIR "~/downloads/tryout"
"Directory for extracting files")
(setq dired-extract-alist
`(
("\\.u\\(ue\\|aa\\)$" . dired-uud)
("\\.jar$" . "jar -xvf %s")
("\\.tar$" . ,(concat "tar -xf %s -C " MY_TRYOUT_DIR))
("\\.tgz$\\|\\.tar\\.g?[zZ]$" . ,(concat "tar -xzf %s -C " MY_TRYOUT_DIR))
("\\.arc$" . "arc x %s ")
("\\.bz2$" . ,(concat "bunzip2 -q %s"))
("\\.rar$" . ,(concat "unrar x %s " MY_TRYOUT_DIR "\\"))
("\\.zip$" . ,(concat "unzip -qq -Ux %s -d " MY_TRYOUT_DIR))
("\\.ear$" . ,(concat "unzip -qq -Ux %s -d " MY_TRYOUT_DIR))
("\\.war$" . ,(concat "unzip -qq -Ux %s -d " MY_TRYOUT_DIR))
("\\.zoo$" . "zoo x. %s ")
("\\.lzh$" . "lha x %s ")
("\\.7z$" . "7z e %s ")
("\\.g?[zZ]$" . "gzip -d %s") ; There is only one file
))

Platform: Ubuntu
Requirements
System:
sudo apt-get install atool
Emacs:
M-x package-list-packages
C-s dired-atool RET
i
x
Solution
1) Mark the files in dired buffer.
2) M-x dired-atool-do-pack
NOTE: Make sure that shell-file-name is set to "/bin/bash".

In answer to the latter question, another tool which can be used to generate a compressed tar file from dired is pack. Mark the desired files and execute pack-dired-do-pack, specifying whatever.tar.gz as the output file name.

Related

How can emacs make a 'open-with' selectable for files?

Using dired in emacs, i would to open (ie; a .png) any file with a list of viewers (selectable by typing) as 'open-with' way...
How can i do that?
Thank you,
Steve,
You should use & to run the command in async: !
will freeze Emacs while the command is running.
Customize dired-guess-shell-alist-user as a guess list for common extensions:
(setq dired-guess-shell-alist-user
'(("\\.pdf\\'" "evince" "okular")
("\\.eps\\'" "evince")
("\\.jpe?g\\'" "eog")
("\\.png\\'" "eog")
("\\.gif\\'" "eog")
("\\.xpm\\'" "eog")
("\\.csv\\'" "libreoffice")
("\\.tex\\'" "pdflatex" "latex")
("\\.\\(?:mp4\\|mkv\\|avi\\|flv\\|ogv\\)\\'" "vlc")
("\\.\\(?:mp3\\|flac\\)\\'" "rhythmbox")
("\\.html?\\'" "firefox")
("\\.cue?\\'" "audacious")))
The first item on the list will be the default choice, e.g. evince
over okular. You can navigate to the other choices with
M-n/M-p.
If you're on Linux, you can try the command that I'm using for this task:
(defvar dired-filelist-cmd
'(("vlc" "-L")))
(defun dired-start-process (cmd &optional file-list)
(interactive
(let ((files (dired-get-marked-files t current-prefix-arg)))
(list
(dired-read-shell-command "& on %s: " current-prefix-arg files)
files)))
(apply
#'start-process
(list cmd nil shell-file-name shell-command-switch
(format "nohup 1>/dev/null 2>/dev/null %s \"%s\""
(if (> (length file-list) 1)
(format "%s %s"
cmd
(cadr (assoc cmd dired-filelist-cmd)))
cmd)
(mapconcat #'expand-file-name file-list "\" \"")))))
It's better than dired-do-async-shell-command that's bound to
&, because the opened files will persist even if you close
Emacs that opened them. I tend to close Emacs more than usual because
often I'm testing stuff and it's faster to restart than to reset to
the default state.
If you can do without a list of viewers, you can hit ! while point is over a file in dired, and you can type the name of a command (with tab completion if your Emacs is new enough). dired will run that command, with the name of the file added at the end.
If the file name shouldn't be at the end of the command, add * wherever it should be, and dired will put it there instead.
For example, hitting ! over foo.png and typing just bar will run bar foo.png, while typing bar * --baz will run bar foo.png --baz.
For most GNU/linux desktops you can use the mediator package which uses the Freedesktop mime-type specifications to automatically present a list of suitable programs for opening a file of some specific extension.

Honor in-file settings for batch export of org files as HTML

I would like to use Emacs in batch mode to export a number of org files to HTML from the command-line. And I would like to get the same result than interactively using C-cC-eh, in particular:
honor file-local variables (such as org-export-publishing-directory)
honor all options specified through #+KEYWORD: headlines
Starting from the example given in org-export-as-html-batch, I got to this point:
emacs --batch \
--visit=/tmp/foo.org \
--eval "(defun safe-local-variable-p (sym val) t)" \
--funcall hack-local-variables \
--eval "(setq org-export-headline-levels 4)" \
--funcall org-export-as-html-batch
However, some problems remain:
I need to explicitly specify the headline level and I fail to see why all other #+OPTIONS are honored (like toc:nil) but not this one
I had to manually trigger file-local variables parsing using hack-local-variables (I guess it is not automatically done in batch mode) but more importantly I had to resort to a hack to mark all local variables as safe (I'm sure there is much space for improvement here).
NB:
In case it matters, I'm using emacs 23.2.1 (Debian Squeeze flavour)
Here is a sample org file on which I tested this:
#+TITLE: Foo
#+OPTIONS: H:4 toc:nil author:nil
* 1
** 2
*** 3
**** 4
# Local Variables:
# org-export-publishing-directory: "/some/where";
# End:
I eventually got the following script, which seems to fulfill all my requirements:
#!/bin/sh
":"; exec emacs --script "$0" -- "$#" # -*-emacs-lisp-*-
;;
;; Usage:
;; org2html FILE1 [FILE2 ...]
;; Mark org-related variables as safe local variables,
;; regardless of their value.
(defun my/always-safe-local-variable (val) t)
(dolist (sym '(org-export-publishing-directory
org-export-html-preamble
org-export-html-postamble))
(put sym 'safe-local-variable 'my/always-safe-local-variable))
(defun my/org-export-as-html (filename)
"Export FILENAME as html, as if `org-export-to-html' had been called
interactively.
This ensures that `org-export-headline-levels' is correctly read from
the #+OPTIONS: headline."
(save-excursion
(find-file filename)
(message "Exporting file `%s' to HTML" filename)
(call-interactively 'org-export-as-html)))
(mapcar 'my/org-export-as-html
(cdr argv)) ;; "--" is the first element of argv
A few notes on this script:
The executable emacs-lisp script trick comes from this question.
The only way I found to use the org-export-headline-levels value from the #+OPTIONS: headline is to call org-export-as-html interactively, instead of org-export-as-html-batch.
hack-local-variables does not need to be explicitly called, provided that local variables are marked as safe before the file is opened.
I think it is better to only mark org-related variables as safe, using the safe-local-variable symbol property.

How to set the default-directory of compilation in Emacs?

I am coding OCaml under Emacs, I have one makefile in the working folder, and several sub-folders containing .ml files. If I launch M-x compile and make works fine on a buffer of makefile, but does not work on a buffer of a .ml file, it gives me an error:
-*- mode: compilation; default-directory: "..." -*-
Compilation started at Fri Jan 27 18:51:35
make -k
make: *** No targets specified and no makefile found. Stop.
Compilation exited abnormally with code 2 at Fri Jan 27 18:51:35
It is understandable because the default-directory is sub-folder which does not contain makefile. Does anyone know how to set the folder of makefile always as the default-directory of compilation?
You can call make with the right arguments:
make -C .. -k
where .. is the path to your Makefile
You can control this from within emacs by writing a function that (temporarily) sets default-directory and calls compile.
(defun compile-in-parent-directory ()
(interactive)
(let ((default-directory
(if (string= (file-name-extension buffer-file-name) "ml")
(concat default-directory "..")
default-directory))))
(call-interactively #'compile))
When using compile-in-parent-directory all ml files will be compiled in the parent directory of where they are. Of course if they are nested deeper you can change the logic to reflect that. In fact there is a version on the EmacsWiki which searches parent directories until it finds a makefile. I found this after I wrote this answer, otherwise I would have just pointed you there. sigh. The good thing about my method is that it's not specific to make so that you can use the same "trick" for other commands.
You can also change the call to compile to be non-interactive if you know exactly what you want the command to be. This would work particularly well if it's bound to a key in the appropriate mode hook.
i use a script like this which allows me to run make from any sub-directory (assuming you are in a posix-like environment). just put this script in your PATH as something like "sub_make.sh" and invoke it the same way you would invoke make:
#!/bin/bash
# search for project base
INIT_DIR=`pwd`
while [ "$PWD" != "/" ] ; do
if [ -e "makefile" ] ; then
break
fi
cd ..
done
if [ ! -e "makefile" ] ; then
echo "Couldn't find 'makefile'!"
exit 1
fi
# indicate where we are now
echo "cd "`pwd`
echo make "$#"
# now run make for real
exec make "$#"
That's what I have in some of my configs :)
(defun* get-closest-pathname (&optional (max-level 3) (file "Makefile"))
(let* ((root (expand-file-name "/"))
(level 0)
(dir (loop
for d = default-directory then (expand-file-name ".." d)
do (setq level (+ level 1))
if (file-exists-p (expand-file-name file d))
return d
if (> level max-level)
return nil
if (equal d root)
return nil)))
(if dir
(expand-file-name file dir)
nil)))
(add-hook 'c-mode-hook
(lambda ()
(unless (file-exists-p "Makefile")
(set (make-local-variable 'compile-command)
(let ((file (file-name-nondirectory buffer-file-name))
(mkfile (get-closest-pathname)))
(if mkfile
(progn (format "cd %s; make -f %s"
(file-name-directory mkfile) mkfile))
(format "%s -c -o %s.o %s %s %s"
(or (getenv "CC") "gcc")
(file-name-sans-extension file)
(or (getenv "CPPFLAGS") "-DDEBUG=9")
(or (getenv "CFLAGS") "-ansi -pedantic -Wall -g")
file)))))))
Matthias Puech has a solution involving a .dir-local file in the project root directory:
((nil . ((eval . (setq default-directory
(locate-dominating-file buffer-file-name
".dir-locals.el")
)))))
It is presumably also possible to use something like: (shell-command-to-string "git rev-parse --show-toplevel") as that innermost bit.
Not a completely general solution w.r.t makefile location, but adding this here for posterity because it solved my particular use-case.
If you use projectile and your makefile is always in the root of your project directory, then you can use projectile-compile-project.
(In my case, I wanted to lint my project, so calling (compile "flake8") would only flake from the current buffer's directory downwards, whereas what I really wanted was linting of the entire project. projectile-compile-project achieves this.)

How do I uncompress/unzip within Emacs

I would like to run unzip (or even zip) within dired or a dired-like buffer. Is there anything like this? I would like something similar as in the Nautilus file manager: i.e., selecting files and then pressing a keystroke to get these files into a new archive file.
Thank you
You've got options...
To uncompress a .zip file, you just need to add to the variable 'dired-compress-file-suffixes
(eval-after-load "dired-aux"
'(add-to-list 'dired-compress-file-suffixes
'("\\.zip\\'" ".zip" "unzip")))
Now the Z key in dired will recognize the .zip extension and uncompress a .zip archive. Already supported are gunzip, bunzip2, uncompress and dictunzip.
If you want to mark files and add them to a .zip archive you can use the following to make z bound to zip the set of marked files:
(eval-after-load "dired"
'(define-key dired-mode-map "z" 'dired-zip-files))
(defun dired-zip-files (zip-file)
"Create an archive containing the marked files."
(interactive "sEnter name of zip file: ")
;; create the zip file
(let ((zip-file (if (string-match ".zip$" zip-file) zip-file (concat zip-file ".zip"))))
(shell-command
(concat "zip "
zip-file
" "
(concat-string-list
(mapcar
'(lambda (filename)
(file-name-nondirectory filename))
(dired-get-marked-files))))))
(revert-buffer)
;; remove the mark on all the files "*" to " "
;; (dired-change-marks 42 ?\040)
;; mark zip file
;; (dired-mark-files-regexp (filename-to-regexp zip-file))
)
(defun concat-string-list (list)
"Return a string which is a concatenation of all elements of the list separated by spaces"
(mapconcat '(lambda (obj) (format "%s" obj)) list " "))
To zip files, open the directory in dired. Mark the files you want to zip with m. Then type
! zip foo.zip * <RET>
To extract an entire archive from dired you can mark a file and run & unzip, just as you would in a shell.
zip-archive mode will allow you to browse zip files in a dired-like fashion. It should come with recent versions of GNU emacs and will be used by default when you visit a file with the .zip extension. From this mode you can extract individual files into a buffer, and from there save them with C-x C-s.

Ignore Emacs auto-generated files in a diff

How do I make diff ignore temporary files like foo.c~? Is there a configuration file that will make ignoring temporaries the default?
More generally: what's the best way to generate a "clean" patch off a tarball? I do this rarely enough (submitting a bug fix to an OSS project by email) that I always struggle with it...
EDIT: OK, the short answer is
diff -ruN -x *~ ...
Is there a better answer? E.g., can this go in a configuration file?
This doesn't strictly answer your question, but you can avoid the problem by configuring Emacs to use a specific directory to keep the backup files in. There are different implementations for Emacs or XEmacs.
In GNU Emacs
(defvar user-temporary-file-directory
(concat temporary-file-directory user-login-name "/"))
(make-directory user-temporary-file-directory t)
(setq backup-by-copying t)
(setq backup-directory-alist
`(("." . ,user-temporary-file-directory)
(,tramp-file-name-regexp nil)))
(setq auto-save-list-file-prefix
(concat user-temporary-file-directory ".auto-saves-"))
(setq auto-save-file-name-transforms
`((".*" ,user-temporary-file-directory t)))
In XEmacs
(require 'auto-save)
(require 'backup-dir)
(defvar user-temporary-file-directory
(concat (temp-directory) "/" (user-login-name)))
(make-directory user-temporary-file-directory t)
(setq backup-by-copying t)
(setq auto-save-directory user-temporary-file-directory)
(setq auto-save-list-file-prefix
(concat user-temporary-file-directory ".auto-saves-"))
(setq bkup-backup-directory-info
`((t ,user-temporary-file-directory full-path)))
You can also remove them all with a simple find command
find . -name “*~” -delete
Note that the asterisk and tilde are in double quotes to stop the shell expanding them.
By the way, these aren't strictly temporary files. They are a backup of the previous version of the file, so you can manually "undo" your last edit at any time in the future.
You can create an ignore file, like this:
core.*
*~
*.o
*.a
*.so
<more file patterns you want to skip>
and then run diff with -X option, like this:
diff -X ignore-file <other diff options you use/need> path1 path2
There used to be a .diffignore file "close" to the Linux kernel (maybe an informal file), but I couldn't find it anymore. Usually you keep using this ignore-file, just adding new patterns you want to ignore.
You can create a small sunction/script to it, like:
#!/bin/bash
olddir="/tmp/old"
newdir="/tmp/new"
pushd $newdir
for files in $(find . -name \*.c)
do
diff $olddir/$file $newdir/$file
done
popd
This is only one way to script this. The simple way. But I think you got the idea.
Other suggestion is configuring in emacs a backup dir, so your backup files go always to the same place, outside your work dir!
The poster has listed this as the 'short answer':
diff -ruN -x *~ ...
but feeding this to shell will cause the * to be globbed before diff is invoked.
This is better:
diff -r -x '*~' dir1 dir2
I omit the -u and -N flags as those are matters of taste and not relevant to the question at hand.