Skip to content

Commit

Permalink
Fixes #102.
Browse files Browse the repository at this point in the history
  • Loading branch information
ArneBachmann committed Mar 3, 2018
1 parent 026e0e5 commit 31899c1
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Subversion Offline Solution (SOS 1.4.7) #
# Subversion Offline Solution (SOS 1.5.0) #

[![Travis badge](https://travis-ci.org/ArneBachmann/sos.svg?branch=master)](https://travis-ci.org/ArneBachmann/sos)
[![Build status](https://ci.appveyor.com/api/projects/status/fe915rtx02buqe4r?svg=true)](https://ci.appveyor.com/project/ArneBachmann/sos)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os, shutil, subprocess, sys, time, unittest
from setuptools import setup, find_packages

RELEASE = "1.4.7"
RELEASE = "1.5.0"

print("sys.argv is %r" % sys.argv)
readmeFile = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'README.md')
Expand Down
59 changes: 35 additions & 24 deletions sos/sos.coco
Original file line number Diff line number Diff line change
Expand Up @@ -804,35 +804,46 @@ def remove(relPath:str, pattern:str, negative:bool = False):

def ls(folder:str? = None, options:str[] = []):
''' List specified directory, augmenting with repository metadata. '''
folder = folder ?? os.getcwd()
m:Metadata = Metadata()
folder = folder ?? os.getcwd()
if '--all' in options: folder = m.root # always start at SOS repo root with --all
recursive:bool = '--recursive' in options or '-r' in options or '--all' in options
patterns:bool = '--patterns' in options or '-p' in options
DOT:str = (DOT_SYMBOL if m.c.useUnicodeFont else " ") * 3
debug(MARKER + "Repository is in %s mode" % ("tracking" if m.track else ("picky" if m.picky else "simple")))
relPath:str = relativize(m.root, os.path.join(folder, "-"))[0]
if relPath.startswith(os.pardir): Exit("Cannot list contents of folder outside offline repository")
trackingPatterns:FrozenSet[str]? = m.getTrackingPatterns() if m.track or m.picky else f{} # for current branch
untrackingPatterns:FrozenSet[str]? = m.getTrackingPatterns(negative = True) if m.track or m.picky else f{} # for current branch
if '--tags' in options:
printo(ajoin("TAG ", sorted(m.tags), nl = "\n"))
return
if '--patterns' in options:
out:str = ajoin("TRK ", [os.path.basename(p) for p in trackingPatterns if os.path.dirname(p).replace(os.sep, SLASH) == relPath], nl = "\n")
if out: printo(out)
if '--tags' in options: # TODO this has nothing to do with "ls" - it's an entirely different command. Move if something like "sos tag" has been implemented
if len(m.tags) > 0: printo(ajoin("TAG ", sorted(m.tags), nl = "\n"))
return
files:List[str] = list(sorted(entry for entry in os.listdir(folder) if os.path.isfile(os.path.join(folder, entry))))
printo("DIR %s" % relPath)
for file in files: # for each file list all tracking patterns that match, or none (e.g. in picky mode after commit)
ignore:str? = None
for ig in m.c.ignores:
if fnmatch.fnmatch(file, ig): ignore = ig; break # remember first match
if ig:
for wl in m.c.ignoresWhitelist:
if fnmatch.fnmatch(file, wl): ignore = None; break # found a white list entry for ignored file, undo ignoring it
matches:List[str] = []
if not ignore:
for pattern in (p for p in trackingPatterns if os.path.dirname(p).replace(os.sep, SLASH) == relPath): # only patterns matching current folder
if fnmatch.fnmatch(file, os.path.basename(pattern)): matches.append(os.path.basename(pattern))
matches.sort(key = (element) -> len(element)) # sort in-place
printo("%s %s%s" % ("IGN" if ignore is not None else ("TRK" if len(matches) > 0 else DOT_SYMBOL * 3), file, " (%s)" % ignore if ignore is not None else (" (%s)" % ("; ".join(matches)) if len(matches) > 0 else "")))
for dirpath, dirnames, _filenames in os.walk(folder):
if not recursive: dirnames.clear() # avoid recursion
dirnames[:] = sorted([decode(d) for d in dirnames])
dirnames[:] = [d for d in dirnames if len([n for n in m.c.ignoreDirs if fnmatch.fnmatch(d, n)]) == 0 or len([p for p in m.c.ignoreDirsWhitelist if fnmatch.fnmatch(d, p)]) > 0] # global ignores

folder = decode(dirpath)
relPath:str = relativize(m.root, os.path.join(folder, "-"))[0]
if patterns:
out:str = ajoin("TRK ", [os.path.basename(p) for p in trackingPatterns if os.path.dirname(p).replace(os.sep, SLASH) == relPath], nl = "\n")
if out: printo("DIR %s\n" % relPath + out)
continue # with next folder
files:List[str] = list(sorted(entry for entry in os.listdir(folder) if os.path.isfile(os.path.join(folder, entry))))
if len(files) > 0: printo("DIR %s" % relPath)
for file in files: # for each file list all tracking patterns that match, or none (e.g. in picky mode after commit)
ignore:str? = None
for ig in m.c.ignores:
if fnmatch.fnmatch(file, ig): ignore = ig; break # remember first match
if ig:
for wl in m.c.ignoresWhitelist:
if fnmatch.fnmatch(file, wl): ignore = None; break # found a white list entry for ignored file, undo ignoring it
matches:List[str] = []
if not ignore:
for pattern in (p for p in trackingPatterns if os.path.dirname(p).replace(os.sep, SLASH) == relPath): # only patterns matching current folder
if fnmatch.fnmatch(file, os.path.basename(pattern)): matches.append(os.path.basename(pattern))
matches.sort(key = (element) -> len(element)) # sort in-place
printo("%s %s%s" % ("IGN" if ignore is not None else ("TRK" if len(matches) > 0 else DOT), file, " (%s)" % ignore if ignore is not None else (" (%s)" % ("; ".join(matches)) if len(matches) > 0 else "")))

def log(options:str[] = []):
''' List previous commits on current branch. '''
Expand Down Expand Up @@ -1009,7 +1020,7 @@ def move(relPath:str, pattern:str, newRelPath:str, newPattern:str, options:List[
m.saveBranches()

def parse(root:str, cwd:str, cmd:str):
''' Main operation. Main has already chdir into VCS root folder, cwd is original working directory for add, rm, mv. '''
''' Main operation. Main has already chdir into SOS root folder, cwd is original working directory for add, rm, mv. '''
debug("Parsing command-line arguments...")
try:
onlys, excps = parseOnlyOptions(cwd, sys.argv) # extracts folder-relative information for changes, commit, diff, switch, update
Expand Down Expand Up @@ -1057,7 +1068,7 @@ def main():
if '--help' in sys.argv or len(sys.argv) < 2: usage(APPNAME, version.__version__)
command:str? = sys.argv[1] if len(sys.argv) > 1 else None
root, vcs, cmd = findSosVcsBase() # root is None if no .sos folder exists up the folder tree (still working online); vcs is checkout/repo root folder; cmd is the VCS base command
debug("Found root folders for SOS|VCS: %s|%s" % (root ?? "-", vcs ?? "-"))
debug("Found root folders for SOS | VCS: %s | %s" % (root ?? "-", vcs ?? "-"))
defaults["defaultbranch"] = vcsBranches.get(cmd, "trunk") ?? "default" # sets dynamic default with SVN fallback
defaults["useChangesCommand"] = cmd == "fossil" # sets dynamic default with SVN fallback
if force_sos or root is not None or (command ?? "")[:2] == "of" or (command ?? "")[:1] in "hv": # in offline mode or just going offline TODO what about git config?
Expand Down
18 changes: 12 additions & 6 deletions sos/tests.coco
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ class Tests(unittest.TestCase):
out = sos.safeSplit(wrapChannels(() -> sos.ls()).replace("\r", ""), "\n")
_.assertInAny("TRK file1 (file*)", out)
_.assertNotInAny("... file1 (file*)", out)
_.assertInAny("··· foo", out)
_.assertInAny(" foo", out)
out = sos.safeSplit(wrapChannels(() -> sos.ls(options = ["--patterns"])).replace("\r", ""), "\n")
_.assertInAny("TRK file*", out)
_.createFile("a", prefix = "sub")
Expand Down Expand Up @@ -817,6 +817,7 @@ class Tests(unittest.TestCase):
_.createFile("foo")
_.createFile("ign1")
_.createFile("ign2")
_.createFile("bar", prefix = "sub")
sos.offline("test") # set up repo in tracking mode (SVN- or gitless-style)
try: sos.config(["set", "ignores", "ign1"]) # define an ignore pattern
except SystemExit as E: _.assertEqual(0, E.code)
Expand All @@ -827,9 +828,14 @@ class Tests(unittest.TestCase):
out = wrapChannels(() -> sos.config(["show"])).replace("\r", "")
_.assertIn(" ignores [global] ['ign1', 'ign2']", out)
out = sos.safeSplit(wrapChannels(() -> sos.ls()).replace("\r", ""), "\n")
_.assertInAny('··· file1', out)
_.assertInAny('··· ign1', out)
_.assertInAny('··· ign2', out)
_.assertInAny(' file1', out)
_.assertInAny(' ign1', out)
_.assertInAny(' ign2', out)
_.assertNotIn('DIR sub', out)
_.assertNotIn(' bar', out)
out = wrapChannels(() -> sos.ls(options = ["--recursive"])).replace("\r", "")
_.assertIn('DIR sub', out)
_.assertIn(' bar', out)
try: sos.config(["rm", "foo", "bar"]); _.fail()
except SystemExit as E: _.assertEqual(1, E.code)
try: sos.config(["rm", "ignores", "foo"]); _.fail()
Expand All @@ -839,9 +845,9 @@ class Tests(unittest.TestCase):
try: sos.config(["unset", "ignoresWhitelist"]) # remove ignore pattern
except SystemExit as E: _.assertEqual(0, E.code)
out = sos.safeSplit(wrapChannels(() -> sos.ls()).replace("\r", ""), "\n")
_.assertInAny('··· ign1', out)
_.assertInAny(' ign1', out)
_.assertInAny('IGN ign2', out)
_.assertNotInAny('··· ign2', out)
_.assertNotInAny(' ign2', out)

def testWhitelist(_):
# TODO test same for simple mode
Expand Down
10 changes: 7 additions & 3 deletions sos/usage.coco
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Usage: {cmd} <command> [<argument>] [<option1>, ...] When operating in of
--strict Always compare entire file contents
online Finish working offline
dump [<path>/]<name[.sos.zip]> Perform (differential) repository dump
[--full] Export the entire repository, don't attempt differential backup
[--skip-nackup] Don't create an archive copy before commencing backup
[--full] Export the entire repository, don't attempt differential backup, if file already exists
[--skip-nackup] Don't create an archive copy before backup

Working with branches:
branch [<name> [<message>]] Create a new branch from current file tree and switch to it
Expand All @@ -45,7 +45,11 @@ Usage: {cmd} <command> [<argument>] [<option1>, ...] When operating in of
--to=branch/revision Take "to" revision as target to compare against (instead of current file tree state)
--ignore-whitespace | --iw Ignore white spaces during comparison
--wrap Wrap text around terminal size instead of shortening
ls [<folder path>] [--patterns|--tags] List file tree and mark changes and tracking status
ls [<folder path>] List file tree and mark changes and tracking status
--patterns Only show tracking patterns
--tags List all repository tags (has nothing to do with file or filepattern listing)
--recursive | -r Recursively list also sub-folders
--all | -a Recursively list all starting from repository root

Defining file patterns:
add[not] <file pattern> Add a tracking pattern to current branch (file pattern). Using addnot adds to tracking blacklist
Expand Down

0 comments on commit 31899c1

Please sign in to comment.