\documentclass[t,noamsthm,xcolor=dvipsnames]{beamer}
\input{preambel}
\title{Mercurial's Query Languages}
\author{Martin Geisler
  \texorpdfstring{\\$\langle$\texttt{mg@aragost.com}$\rangle$}
                 {<mg@aragost.com>}}
\date{gearconf 2011}

\begin{document}

\begin{frame}[plain]
  \maketitle
  \begin{tikzpicture}[overlay, remember picture]
    \node[above right] at (current page.south west)
         {\includegraphics[height=3cm]{pixelman-front}};
  \end{tikzpicture}
\end{frame}

\begin{frame}{Outline}
  \tableofcontents
\end{frame}

\section{Introduction}

\section{Revision Sets}

\subsection{Predicates}

\begin{frame}[fragile]{Predicates}
  Predicates select changesets for inclusion in the resulting set:
  \begin{itemize}
  \item Changeset metadata: \cmd{closed()}, \cmd{head()},
    \cmd{merge()}, \cmd{author(string)}, \cmd{date(interval)},

Closed heads:
\begin{lstlisting}
$ hg log -r "head() and closed()"
\end{lstlisting}

Reopened branches:
\begin{lstlisting}
$ hg log -r "closed() and not head()"
\end{lstlisting}

\begin{lstlisting}
$ hg log -r "author('Martin') and merge()"
\end{lstlisting}

  \end{itemize}

  bisected(string)
  grep(regex)
  keyword(string)

  \cmd{adds(pattern)}
  \cmd{contains(pattern)}
  \cmd{file(pattern)}
  \cmd{filelog(pattern)}
  \cmd{modifies(pattern)}
  \cmd{removes(pattern)}


\end{frame}



\begin{frame}{Functions}
  ancestor(single, single)
  ancestors(set)
  children(set)
  descendants(set)
  follow([file])

  heads(set)

  outgoing([path])

  p1([set])
  p2([set])
  parents([set])
  present(set)
  roots(set)
\end{frame}

\begin{frame}{Final Touches on Your Query}
  Trimming, cutting, manipulating the set:
  \begin{itemize}[<+->]
    \item \cmd{max(set)}, \cmd{min(set)}: the changeset with
      minimum/maximum revision number in the set
    \item \cmd{reverse(set)}: the set is an ordered set; this reverses
      it
    \item \cmd{limit(set, n)}, \cmd{last(set, n)}: the first/last
      $n$ changesets
    \item \cmd{sort(set[, [-]key...])}: sorting the set by revision
      number, branch name, changeset message, user name, or date
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Solving Ambiguities}
  When you do \cmd{hg log -r "foo"}, Mercurial checks
  \begin{enumerate}
  %\item revision number
  %\item full changeset ID
  \item is \cmd{foo} a bookmark?
  \item is \cmd{foo} a tag?
  \item is \cmd{foo} a branch name?
  %\item partial changeset ID
  \end{enumerate}
  First match wins.

  You can override this using predicates:
  \begin{itemize}[<+->]
  %\item \cmd{rev(number)}
  %\item \cmd{id(hash)}
  \item \cmd{bookmark([name])}, \cmd{tag([name])}: the changeset with
    the given bookmark or tag, or all bookmarked/tagged changesets
  \item \cmd{branch(name)}: changesets on the given branch
  \item \cmd{branch(set)}: changesets on the branches of the given set,
    normally used with a single changeset:
\begin{lstlisting}
$ hg log -r "branch(tip)"
\end{lstlisting}
  \end{itemize}
\end{frame}

\subsection{Operators}

\begin{frame}{Operators}

\end{frame}

\begin{frame}[fragile]{Examples}
  \begin{itemize}
  \item Changes that need to be merged into the default branch:
\begin{lstlisting}
$ hg log -r "ancestors(stable) - ancestors(default)"
$ hg log -r "::stable - ::default"
\end{lstlisting}

\item Heads on the current branch:
\begin{lstlisting}
$ hg log -r "head() and branch(.)"
\end{lstlisting}

\item Open heads on the current branch:
\begin{lstlisting}
$ hg log -r "head() and branch(.) and not closed()"
\end{lstlisting}

\item Bugfixes that are not in a tagged release:
\begin{lstlisting}
$ hg log -r "keyword(bug) and not ::tagged()"
\end{lstlisting}


  \end{itemize}
\end{frame}


\section{File Sets}

\begin{frame}{Selecting Files}
  \begin{itemize}
  \item select files from working copy
  \item select files from old revisions
  \item might be part of Mercurial 1.9 (July) or 2.0 (November)
  \end{itemize}
\end{frame}

\begin{frame}
  File sets give an amazing flexibility.
\end{frame}

\begin{frame}[fragile]{Working Copy Status}
  The \cmd{hg status} command lets you select files:
\begin{lstlisting}
$ hg status
M index.html
A logo.png
$ hg status --added
A logo.png
\end{lstlisting}

How do you see the change to \path{index.html} without seeing the diff
of the added \path{logo.png} file? You do:
\begin{lstlisting}
$ hg diff $(hg status --no-status --modified)
\end{lstlisting}

With file sets you can do
\begin{lstlisting}
$ hg diff "set:modified()"
\end{lstlisting}
and it will work on all platforms.

\end{frame}

\begin{frame}[fragile]{Working Copy Status}
The proposed predicates are:
\begin{itemize}[<+->]

\item status flags: \cmd{modified()}, \cmd{added()}, \cmd{removed()},
  \cmd{deleted()}, \cmd{unknown()}, \cmd{ignored()}, \cmd{clean()}

\item copied files: \cmd{copied()}

\item tracked files that \emph{would} be ignored: \cmd{ignorable()}

\item all tracked files:
  \cmd{tracked()}

\item after a merge: \cmd{conflicted()} and \cmd{not conflicted()}

\end{itemize}
\end{frame}

\begin{frame}[fragile]
  We can replace the \cmd{find} Unix command:
  \begin{itemize}
  \item \cmd{glob(P)} instead of \cmd{find -path P}
  \item \cmd{regex(P)} instead of \cmd{find -regex P}
  \end{itemize}
  Remember that this also works on old revisions:
\begin{lstlisting}
$ hg status -r 1.0::2.0 "set:glob(src/*.h)"
A src/foo.h
M src/bar.h
\end{lstlisting}
This shows that \path{foo.h} is a new header file in version 2.0.
\end{frame}

\begin{frame}
  Other \cmd{find}-like predicates will be:
  \begin{itemize}
    \item file type: \cmd{executable()}, \cmd{symlink()},
    \item permissions: \cmd{perm()}, \cmd{owner()}
    \item other: \cmd{date()}, \cmd{size()}
  \end{itemize}
\end{frame}

\begin{frame}
  Matching files by content:
  \begin{itemize}
  \item \cmd{grep()}: like the Unix \cmd{grep} we all love
  \item \cmd{contains()}: simple sub-string matching
  \item \cmd{binary()}, \cmd{text()}
  \item \cmd{decodes()}: check if file can be decoded with the given
    character set, such as UTF-8, UTF-16, \dots
  \item \cmd{eol()}: line-ending type, Unix (\cmd{LF}) or DOS (\cmd{CRLF})
  \end{itemize}
\end{frame}



\begin{frame}[fragile]{Working Copy Predicates}
\begin{lstlisting}
$ hg status
? logo.png
? index.html
$ hg status "set:unknown() and not binary()"
? index.html
\end{lstlisting}
\end{frame}


\begin{frame}[fragile]{Working Copy Predicates}
\begin{lstlisting}
$ hg status -c 100 "set:decodes('UTF-8')"
M plan.txt
\end{lstlisting}
\end{frame}

\begin{frame}
  Future extensions:
  \begin{itemize}
  \item \cmd{magic()}: recognize files based on file content, like the
    \cmd{file} program in Unix
  \item \cmd{locked()}: files locked for exclusive access by my
    \ext{lock} extension
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Implementation}
  When a revision set is evaluated it is:
  \begin{description}[<+->]
  \item[tokenized:] split input into operators, symbols, strings
  \item[parsed:] build parse tree based on operator precedence
  \item[optimized:] reorders parse tree to evaluate cheap parts first:
\begin{lstlisting}
contains("README") and 1.0::1.5
\end{lstlisting}
starts with a manifest-based query --- reorder to:
\begin{lstlisting}
1.0::1.5 and contains("README")
\end{lstlisting}
  \item[executed:] go through tree and evaluate predicates
  \end{description}
\end{frame}


\appendix
\newcounter{finalframe}
\setcounter{finalframe}{\value{framenumber}}

\setcounter{framenumber}{\value{finalframe}}

\end{document}

% LocalWords:  changeset changesets
