1"""
2Subversion SCM
3"""
4
5import re
6
7import salt.utils.args
8import salt.utils.path
9from salt.exceptions import CommandExecutionError
10
11_INI_RE = re.compile(r"^([^:]+):\s+(\S.*)$", re.M)
12
13
14def __virtual__():
15    """
16    Only load if svn is installed
17    """
18    if salt.utils.path.which("svn") is None:
19        return (False, "The svn execution module cannot be loaded: svn unavailable.")
20    else:
21        return True
22
23
24def _run_svn(cmd, cwd, user, username, password, opts, **kwargs):
25    """
26    Execute svn
27    return the output of the command
28
29    cmd
30        The command to run.
31
32    cwd
33        The path to the Subversion repository
34
35    user
36        Run svn as a user other than what the minion runs as
37
38    username
39        Connect to the Subversion server as another user
40
41    password
42        Connect to the Subversion server with this password
43
44        .. versionadded:: 0.17.0
45
46    opts
47        Any additional options to add to the command line
48
49    kwargs
50        Additional options to pass to the run-cmd
51    """
52    cmd = ["svn", "--non-interactive", cmd]
53
54    options = list(opts)
55    if username:
56        options.extend(["--username", username])
57    if password:
58        options.extend(["--password", password])
59    cmd.extend(options)
60
61    result = __salt__["cmd.run_all"](
62        cmd, python_shell=False, cwd=cwd, runas=user, **kwargs
63    )
64
65    retcode = result["retcode"]
66
67    if retcode == 0:
68        return result["stdout"]
69    raise CommandExecutionError(result["stderr"] + "\n\n" + " ".join(cmd))
70
71
72def info(cwd, targets=None, user=None, username=None, password=None, fmt="str"):
73    """
74    Display the Subversion information from the checkout.
75
76    cwd
77        The path to the Subversion repository
78
79    targets : None
80        files, directories, and URLs to pass to the command as arguments
81        svn uses '.' by default
82
83    user : None
84        Run svn as a user other than what the minion runs as
85
86    username : None
87        Connect to the Subversion server as another user
88
89    password : None
90        Connect to the Subversion server with this password
91
92        .. versionadded:: 0.17.0
93
94    fmt : str
95        How to fmt the output from info.
96        (str, xml, list, dict)
97
98    CLI Example:
99
100    .. code-block:: bash
101
102        salt '*' svn.info /path/to/svn/repo
103    """
104    opts = list()
105    if fmt == "xml":
106        opts.append("--xml")
107    if targets:
108        opts += salt.utils.args.shlex_split(targets)
109    infos = _run_svn("info", cwd, user, username, password, opts)
110
111    if fmt in ("str", "xml"):
112        return infos
113
114    info_list = []
115    for infosplit in infos.split("\n\n"):
116        info_list.append(_INI_RE.findall(infosplit))
117
118    if fmt == "list":
119        return info_list
120    if fmt == "dict":
121        return [dict(tmp) for tmp in info_list]
122
123
124def checkout(cwd, remote, target=None, user=None, username=None, password=None, *opts):
125    """
126    Download a working copy of the remote Subversion repository
127    directory or file
128
129    cwd
130        The path to the Subversion repository
131
132    remote : None
133        URL to checkout
134
135    target : None
136        The name to give the file or directory working copy
137        Default: svn uses the remote basename
138
139    user : None
140        Run svn as a user other than what the minion runs as
141
142    username : None
143        Connect to the Subversion server as another user
144
145    password : None
146        Connect to the Subversion server with this password
147
148        .. versionadded:: 0.17.0
149
150    CLI Example:
151
152    .. code-block:: bash
153
154        salt '*' svn.checkout /path/to/repo svn://remote/repo
155    """
156    opts += (remote,)
157    if target:
158        opts += (target,)
159    return _run_svn("checkout", cwd, user, username, password, opts)
160
161
162def switch(cwd, remote, target=None, user=None, username=None, password=None, *opts):
163    """
164    .. versionadded:: 2014.1.0
165
166    Switch a working copy of a remote Subversion repository
167    directory
168
169    cwd
170        The path to the Subversion repository
171
172    remote : None
173        URL to switch
174
175    target : None
176        The name to give the file or directory working copy
177        Default: svn uses the remote basename
178
179    user : None
180        Run svn as a user other than what the minion runs as
181
182    username : None
183        Connect to the Subversion server as another user
184
185    password : None
186        Connect to the Subversion server with this password
187
188    CLI Example:
189
190    .. code-block:: bash
191
192        salt '*' svn.switch /path/to/repo svn://remote/repo
193    """
194    opts += (remote,)
195    if target:
196        opts += (target,)
197    return _run_svn("switch", cwd, user, username, password, opts)
198
199
200def update(cwd, targets=None, user=None, username=None, password=None, *opts):
201    """
202    Update the current directory, files, or directories from
203    the remote Subversion repository
204
205    cwd
206        The path to the Subversion repository
207
208    targets : None
209        files and directories to pass to the command as arguments
210        Default: svn uses '.'
211
212    user : None
213        Run svn as a user other than what the minion runs as
214
215    password : None
216        Connect to the Subversion server with this password
217
218        .. versionadded:: 0.17.0
219
220    username : None
221        Connect to the Subversion server as another user
222
223    CLI Example:
224
225    .. code-block:: bash
226
227        salt '*' svn.update /path/to/repo
228    """
229    if targets:
230        opts += tuple(salt.utils.args.shlex_split(targets))
231    return _run_svn("update", cwd, user, username, password, opts)
232
233
234def diff(cwd, targets=None, user=None, username=None, password=None, *opts):
235    """
236    Return the diff of the current directory, files, or directories from
237    the remote Subversion repository
238
239    cwd
240        The path to the Subversion repository
241
242    targets : None
243        files and directories to pass to the command as arguments
244        Default: svn uses '.'
245
246    user : None
247        Run svn as a user other than what the minion runs as
248
249    username : None
250        Connect to the Subversion server as another user
251
252    password : None
253        Connect to the Subversion server with this password
254
255        .. versionadded:: 0.17.0
256
257    CLI Example:
258
259    .. code-block:: bash
260
261        salt '*' svn.diff /path/to/repo
262    """
263    if targets:
264        opts += tuple(salt.utils.args.shlex_split(targets))
265    return _run_svn("diff", cwd, user, username, password, opts)
266
267
268def commit(cwd, targets=None, msg=None, user=None, username=None, password=None, *opts):
269    """
270    Commit the current directory, files, or directories to
271    the remote Subversion repository
272
273    cwd
274        The path to the Subversion repository
275
276    targets : None
277        files and directories to pass to the command as arguments
278        Default: svn uses '.'
279
280    msg : None
281        Message to attach to the commit log
282
283    user : None
284        Run svn as a user other than what the minion runs as
285
286    username : None
287        Connect to the Subversion server as another user
288
289    password : None
290        Connect to the Subversion server with this password
291
292        .. versionadded:: 0.17.0
293
294    CLI Example:
295
296    .. code-block:: bash
297
298        salt '*' svn.commit /path/to/repo
299    """
300    if msg:
301        opts += ("-m", msg)
302    if targets:
303        opts += tuple(salt.utils.args.shlex_split(targets))
304    return _run_svn("commit", cwd, user, username, password, opts)
305
306
307def add(cwd, targets, user=None, username=None, password=None, *opts):
308    """
309    Add files to be tracked by the Subversion working-copy checkout
310
311    cwd
312        The path to the Subversion repository
313
314    targets : None
315        files and directories to pass to the command as arguments
316
317    user : None
318        Run svn as a user other than what the minion runs as
319
320    username : None
321        Connect to the Subversion server as another user
322
323    password : None
324        Connect to the Subversion server with this password
325
326        .. versionadded:: 0.17.0
327
328    CLI Example:
329
330    .. code-block:: bash
331
332        salt '*' svn.add /path/to/repo /path/to/new/file
333    """
334    if targets:
335        opts += tuple(salt.utils.args.shlex_split(targets))
336    return _run_svn("add", cwd, user, username, password, opts)
337
338
339def remove(cwd, targets, msg=None, user=None, username=None, password=None, *opts):
340    """
341    Remove files and directories from the Subversion repository
342
343    cwd
344        The path to the Subversion repository
345
346    targets : None
347        files, directories, and URLs to pass to the command as arguments
348
349    msg : None
350        Message to attach to the commit log
351
352    user : None
353        Run svn as a user other than what the minion runs as
354
355    username : None
356        Connect to the Subversion server as another user
357
358    password : None
359        Connect to the Subversion server with this password
360
361        .. versionadded:: 0.17.0
362
363    CLI Example:
364
365    .. code-block:: bash
366
367        salt '*' svn.remove /path/to/repo /path/to/repo/remove
368    """
369    if msg:
370        opts += ("-m", msg)
371    if targets:
372        opts += tuple(salt.utils.args.shlex_split(targets))
373    return _run_svn("remove", cwd, user, username, password, opts)
374
375
376def status(cwd, targets=None, user=None, username=None, password=None, *opts):
377    """
378    Display the status of the current directory, files, or
379    directories in the Subversion repository
380
381    cwd
382        The path to the Subversion repository
383
384    targets : None
385        files, directories, and URLs to pass to the command as arguments
386        Default: svn uses '.'
387
388    user : None
389        Run svn as a user other than what the minion runs as
390
391    username : None
392        Connect to the Subversion server as another user
393
394    password : None
395        Connect to the Subversion server with this password
396
397        .. versionadded:: 0.17.0
398
399    CLI Example:
400
401    .. code-block:: bash
402
403        salt '*' svn.status /path/to/repo
404    """
405    if targets:
406        opts += tuple(salt.utils.args.shlex_split(targets))
407    return _run_svn("status", cwd, user, username, password, opts)
408
409
410def export(
411    cwd,
412    remote,
413    target=None,
414    user=None,
415    username=None,
416    password=None,
417    revision="HEAD",
418    *opts
419):
420    """
421    Create an unversioned copy of a tree.
422
423    cwd
424        The path to the Subversion repository
425
426    remote : None
427        URL and path to file or directory checkout
428
429    target : None
430        The name to give the file or directory working copy
431        Default: svn uses the remote basename
432
433    user : None
434        Run svn as a user other than what the minion runs as
435
436    username : None
437        Connect to the Subversion server as another user
438
439    password : None
440        Connect to the Subversion server with this password
441
442        .. versionadded:: 0.17.0
443
444    CLI Example:
445
446    .. code-block:: bash
447
448        salt '*' svn.export /path/to/repo svn://remote/repo
449    """
450    opts += (remote,)
451    if target:
452        opts += (target,)
453    revision_args = "-r"
454    opts += (
455        revision_args,
456        str(revision),
457    )
458    return _run_svn("export", cwd, user, username, password, opts)
459