1# -*- coding: utf-8 -*-
2# Gitless - a version control system built on top of Git
3# Licensed under MIT
4
5"""gl status - Show the status of files in the repo."""
6
7
8from __future__ import unicode_literals
9
10import os
11
12from clint.textui import colored
13
14from gitless import core
15
16from . import helpers, pprint
17
18
19def parser(subparsers, repo):
20  """Adds the status parser to the given subparsers object."""
21  desc = 'show status of the repo'
22  status_parser = subparsers.add_parser(
23      'status', help=desc, description=desc.capitalize())
24  status_parser.add_argument(
25      'paths', nargs='*', help='the specific path(s) to status',
26      action=helpers.PathProcessor, repo=repo)
27  status_parser.set_defaults(func=main)
28
29
30def main(args, repo):
31  curr_b = repo.current_branch
32  pprint.msg('On branch {0}, repo-directory {1}'.format(
33    colored.green(curr_b.branch_name), colored.green('//' + repo.cwd)))
34
35  if curr_b.merge_in_progress:
36    pprint.blank()
37    _print_conflict_exp('merge')
38  elif curr_b.fuse_in_progress:
39    pprint.blank()
40    _print_conflict_exp('fuse')
41
42  tracked_mod_list = []
43  untracked_list = []
44  paths = frozenset(args.paths)
45  for f in curr_b.status():
46    if paths and (f.fp not in paths):
47      continue
48    if f.type == core.GL_STATUS_TRACKED and f.modified:
49      tracked_mod_list.append(f)
50    elif f.type == core.GL_STATUS_UNTRACKED:
51      untracked_list.append(f)
52
53  relative_paths = True  # git seems to default to true
54  try:
55    relative_paths = repo.config.get_bool('status.relativePaths')
56  except KeyError:
57    pass
58
59  pprint.blank()
60  tracked_mod_list.sort(key=lambda f: f.fp)
61  _print_tracked_mod_files(tracked_mod_list, relative_paths, repo)
62  pprint.blank()
63  pprint.blank()
64  untracked_list.sort(key=lambda f: f.fp)
65  _print_untracked_files(untracked_list, relative_paths, repo)
66  return True
67
68
69def _print_tracked_mod_files(tracked_mod_list, relative_paths, repo):
70  pprint.msg('Tracked files with modifications:')
71  pprint.exp('these will be automatically considered for commit')
72  pprint.exp(
73      'use gl untrack f if you don\'t want to track changes to file f')
74  pprint.exp(
75      'if file f was committed before, use gl checkout f to discard '
76      'local changes')
77  pprint.blank()
78
79  if not tracked_mod_list:
80    pprint.item('There are no tracked files with modifications to list')
81    return
82
83  root = repo.root
84  for f in tracked_mod_list:
85    exp = ''
86    color = colored.yellow
87    if not f.exists_at_head:
88      exp = ' (new file)'
89      color = colored.green
90    elif not f.exists_in_wd:
91      exp = ' (deleted)'
92      color = colored.red
93    elif f.in_conflict:
94      exp = ' (with conflicts)'
95      color = colored.cyan
96
97    fp = os.path.relpath(os.path.join(root, f.fp)) if relative_paths else f.fp
98    if fp == '.':
99      continue
100
101    pprint.item(color(fp), opt_text=exp)
102
103
104def _print_untracked_files(untracked_list, relative_paths, repo):
105  pprint.msg('Untracked files:')
106  pprint.exp('these won\'t be considered for commit')
107  pprint.exp('use gl track f if you want to track changes to file f')
108  pprint.blank()
109
110  if not untracked_list:
111    pprint.item('There are no untracked files to list')
112    return
113
114  root = repo.root
115  for f in untracked_list:
116    exp = ''
117    color = colored.blue
118    if f.in_conflict:
119      exp = ' (with conflicts)'
120      color = colored.cyan
121    elif f.exists_at_head:
122      color = colored.magenta
123      if f.exists_in_wd:
124        exp = ' (exists at head)'
125      else:
126        exp = ' (exists at head but not in working directory)'
127
128    fp = os.path.relpath(os.path.join(root, f.fp)) if relative_paths else f.fp
129    if fp == '.':
130      continue
131
132    pprint.item(color(fp), opt_text=exp)
133
134
135def _print_conflict_exp(op):
136  pprint.msg(
137      'You are in the middle of a {0}; all conflicts must be resolved before '
138      'commiting'.format(op))
139  pprint.exp(
140      'use gl {0} --abort to go back to the state before the {0}'.format(op))
141  pprint.exp('use gl resolve f to mark file f as resolved')
142  pprint.exp('once you solved all conflicts do gl commit to continue')
143  pprint.blank()
144