Skip to content

Commit

Permalink
Fixes #113. Fixes #111.
Browse files Browse the repository at this point in the history
  • Loading branch information
ArneBachmann committed Jan 4, 2018
1 parent d805e54 commit ec62d76
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 27 deletions.
12 changes: 3 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Subversion Offline Solution (SOS 1.1.2) #
# Subversion Offline Solution (SOS 1.1.3) #

[![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)
[![Code coverage badge](https://coveralls.io/repos/github/ArneBachmann/sos/badge.svg?branch=master)](https://coveralls.io/github/ArneBachmann/sos?branch=master)
[![PyPI badge](https://img.shields.io/pypi/v/sos-vcs.svg)](https://badge.fury.io/py/sos-vcs)

- License: [MPL-2.0](https://www.mozilla.org/en-US/MPL/2.0/)
- [Documentation](http://sos-vcs.net), [Code Repository](https://github.com/ArneBachmann/sos)
- [Documentation](http://sos-vcs.net) (official website), [Code Repository](https://github.com/ArneBachmann/sos) (at Github)
- [Buy a coffee](http://PayPal.Me/ArneBachmann/) for the developer to show your appreciation!

### List of Abbreviations and Definitions ###
Expand Down Expand Up @@ -139,14 +139,8 @@ By means of the `sos config set <key> <value>` command, you can set these flags
- `sos update` will **not warn** if local changes are present! This is a noteworthy exception to the failsafe approach taken for most other commands


## FAQ ##
> Q: I don't want to risk data loss in case SOS has some undiscovered bugs. What can I do?
>
> A: Configure SOS to store all versioned files as plain file copies instead of compressed artifacts: `sos offline --plain` for one repository only, or `sos config set compress off` to define a user-preset before going offline. Plain repositories simply copy files when branching and/or versioning; note, however, that filenames will be hashed and stored in the metadata file instead (which is human-readable, thankfully).

## Hints and Tipps ##
- Too speed up going offline, use the `sos offline --plain` option: It may reduce the time for going offline by a larger factor (in tests on a small laptop with BTRFS it was 30 times faster due to avoiding Python having to compress all versioned file contents)
- To save space when going offline, use the option `sos offline --compress`: It may increase the time for going offline by a larger factor (e.g. 10x), but will also reduce the amount of storage needed to version files. To enable this option for all offline repositories, use `sos config set compress on`
- When specifying file patterns including glob markers on the command line, make sure you quote them correctly. On linux (bash, sh, zsh), put your patterns into quote (`"`), otherwise the shell will replace file patterns by any matching filenames instead of forwarding the pattern literally to SOS
- Many commands can be shortened to three, two or even one initial letters
- It might in some cases be a good idea to go offline one folder higher up in the file tree than your base working folder to care for potential deletions or renames
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import os, shutil, subprocess, sys, time, unittest
from setuptools import setup, find_packages

RELEASE = "1.1.2"
RELEASE = "1.1.3"

print("sys.argv is %r" % sys.argv)
readmeFile = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'README.md')
Expand Down Expand Up @@ -42,7 +42,7 @@

import sos.sos as sos

if 'test' in sys.argv : print("Warning: Won't build distribution after running unit tests")
if 'test' in sys.argv : print("Warning: Won't create distribution archive after running unit tests")

if 'sdist' in sys.argv:
print("Cleaning up old archives for twine upload")
Expand Down
26 changes: 15 additions & 11 deletions sos/sos.coco
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# Standard modules
import codecs, collections, fnmatch, json, logging, mimetypes, os, shutil, sys, time
import time; START_TIME = time.time()
import codecs, collections, fnmatch, json, logging, mimetypes, os, shutil, sys
try:
from typing import Any, Dict, FrozenSet, IO, Iterator, List, Set, Tuple, Type, Union # only required for mypy
except: pass # typing not available (e.g. Python 2)
Expand All @@ -23,7 +24,7 @@ except: configr = None # declare as undefined

# Constants
APPNAME:str = "Subversion Offline Solution V%s (C) Arne Bachmann" % version.__release_version__
defaults = Accessor({"strict": False, "track": False, "picky": False, "compress": True, "tags": [], "texttype": [], "bintype": [], "ignoreDirs": [".*", "__pycache__"], "ignoreDirsWhitelist": [], "ignores": ["__coconut__.py", "*.bak", "*.py[cdo]", "*.class", ".fslckout"], "ignoresWhitelist": []})
defaults = Accessor({"strict": False, "track": False, "picky": False, "compress": False, "tags": [], "texttype": [], "bintype": [], "ignoreDirs": [".*", "__pycache__"], "ignoreDirsWhitelist": [], "ignores": ["__coconut__.py", "*.bak", "*.py[cdo]", "*.class", ".fslckout"], "ignoresWhitelist": []})
termWidth = getTermWidth() - 1 # uses curses or returns conservative default of 80


Expand All @@ -50,7 +51,7 @@ Usage: {cmd} <command> [<argument>] [<option1>, ...] When operating in of

Available commands:
offline [<name>] Start working offline, creating a branch (named <name>), default name depending on VCS
--plain Don't compress versioned files (same as `sos config set compress off`)
--compress Compress versioned files (same as `sos config set compress on && sos offline`)
--track Setup SVN-style mode: users add/remove tracking patterns per branch
--picky Setup Git-style mode: users pick files for each operation
online Finish working offline
Expand Down Expand Up @@ -103,6 +104,7 @@ Usage: {cmd} <command> [<argument>] [<option1>, ...] When operating in of
--{cmd} When executing {CMD} not being offline, pass arguments to {CMD} instead (e.g. {cmd} --{cmd} config set key value.)
--log Enable logging details
--verbose Enable verbose output""".format(appname = APPNAME, cmd = "sos", CMD = "SOS"))
Exit(code = 0)

# Main data class
#@runtime_validation
Expand Down Expand Up @@ -429,10 +431,10 @@ def offline(argument:str? = None, options:str[] = []) -> None:
else: os.unlink(resource)
except: Exit("Cannot reliably remove previous repository contents. Please remove .sos folder manually prior to going offline")
m:Metadata = Metadata(os.getcwd())
if '--plain' in options or not m.c.compress: m.compress = False # plain file copies instead of compressed ones
if '--picky' in options or m.c.picky: m.picky = True # Git-like
elif '--track' in options or m.c.track: m.track = True # Svn-like
if '--strict' in options or m.c.strict: m.strict = True # always hash contents
if '--compress' in options or m.c.compress: m.compress = True # plain file copies instead of compressed ones
if '--picky' in options or m.c.picky: m.picky = True # Git-like
elif '--track' in options or m.c.track: m.track = True # Svn-like
if '--strict' in options or m.c.strict: m.strict = True # always hash contents
debug("Preparing offline repository...")
m.createBranch(0, argument ?? str(defaults["defaultbranch"]), initialMessage = "Offline repository created on %s" % strftime()) # main branch's name may be None (e.g. for fossil)
m.branch = 0
Expand Down Expand Up @@ -873,22 +875,22 @@ def parse(root:str, cwd:str):
elif command[:1] == "u": update(argument, options, onlys, excps)
elif command[:1] == "v": usage(short = True)
else: Exit("Unknown command '%s'" % command)
Exit(code = 0)
except Exception, RuntimeError as E:
print(str(E))
import traceback
traceback.print_exc()
traceback.print_stack()
try: traceback.print_last()
except: pass
print("An internal error occurred in SOS. Please report above message to the project maintainer at https://github.com/ArneBachmann/sos/issues via 'New Issue'.\nPlease state your installed version via 'sos version', and what you were doing.")
sys.exit(0)
Exit("An internal error occurred in SOS. Please report above message to the project maintainer at https://github.com/ArneBachmann/sos/issues via 'New Issue'.\nPlease state your installed version via 'sos version', and what you were doing.")

def main() -> None:
global debug, info, warn, error
logging.basicConfig(level = level, stream = sys.stderr, format = ("%(asctime)-23s %(levelname)-8s %(name)s:%(lineno)d | %(message)s" if '--log' in sys.argv else "%(message)s"))
_log = Logger(logging.getLogger(__name__)); debug, info, warn, error = _log.debug, _log.info, _log.warn, _log.error
for option in (o for o in ['--log', '--verbose', '-v', '--sos'] if o in sys.argv): sys.argv.remove(option) # clean up program arguments
if '--help' in sys.argv or len(sys.argv) < 2: usage(); Exit()
if '--help' in sys.argv or len(sys.argv) < 2: usage()
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 ?? ""))
Expand Down Expand Up @@ -916,7 +918,9 @@ def main() -> None:


# Main part
level = logging.DEBUG if os.environ.get("DEBUG", "False").lower() == "true" or '--verbose' in sys.argv or '-v' in sys.argv else logging.INFO
verbose = lateBinding["verbose"] = os.environ.get("DEBUG", "False").lower() == "true" or '--verbose' in sys.argv or '-v' in sys.argv # imported from utility, and only modified here
lateBinding["start"] = START_TIME
level = logging.DEBUG if verbose else logging.INFO
force_sos:bool = '--sos' in sys.argv
force_vcs:bool = '--vcs' in sys.argv
_log:logging.Logger = Logger(logging.getLogger(__name__)); debug, info, warn, error = _log.debug, _log.info, _log.warn, _log.error
Expand Down
10 changes: 6 additions & 4 deletions sos/tests.coco
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ class Tests(unittest.TestCase):
sos.tokenizeGlobPatterns("*xb?c", "*x?bc") # succeeds, because glob patterns match (differ only in position)
try: sos.tokenizeGlobPatterns("a???b*", "ab???*"); _.fail() # succeeds, because glob patterns match (differ only in position)
except: pass

def testConvertGlobFiles(_):
_.assertEqual(["xxayb", "aacb"], [r[1] for r in sos.convertGlobFiles(["axxby", "aabc"], *sos.tokenizeGlobPatterns("a*b?", "*a?b"))])
_.assertEqual(["1qq2ww3", "1abcbx2xbabc3"], [r[1] for r in sos.convertGlobFiles(["qqxbww", "abcbxxbxbabc"], *sos.tokenizeGlobPatterns("*xb*", "1*2*3"))])
Expand Down Expand Up @@ -625,7 +625,7 @@ class Tests(unittest.TestCase):

def testCompression(_):
_.createFile(1)
sos.offline("master", options = ["--plain", "--force"])
sos.offline("master", options = ["--force"])
_.assertTrue(_.existsFile(branchFolder(0, 0) + os.sep + "b9ee10a87f612e299a6eb208210bc0898092a64c48091327cc2aaeee9b764ffa", b"x" * 10))
setRepoFlag("compress", True) # was plain = uncompressed before
_.createFile(2)
Expand Down Expand Up @@ -745,8 +745,10 @@ class Tests(unittest.TestCase):
sos.delete("added", "--force") # should succeed

def testUsage(_):
sos.usage()
sos.usage(short = True)
try: sos.usage(); _.fail() # TODO expect sys.exit(0)
except: pass
try: sos.usage(short = True); _.fail()
except: pass

def testOnly(_):
_.assertEqual((f{"./A", "x/B"}, f{"./C"}), sos.parseOnlyOptions(".", ["abc", "def", "--only", "A", "--x", "--only", "x/B", "--except", "C", "--only"]))
Expand Down
3 changes: 2 additions & 1 deletion sos/utility.coco
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ SVN = "svn"
SLASH = "/"
vcsFolders:Dict[str,str] = {".svn": SVN, ".git": "git", ".bzr": "bzr", ".hg": "hg", ".fslckout": "fossil", "_FOSSIL_": "fossil", ".CVS": "cvs"}
vcsBranches:Dict[str,str?] = {SVN: "trunk", "git": "master", "bzr": "trunk", "hg": "default", "fossil": None, "cvs": None}
lateBinding:Accessor = Accessor({"verbose": False, "start": 0})


# Value types
Expand Down Expand Up @@ -109,7 +110,7 @@ def eoldet(file:bytes) -> bytes? =
if cr > lf: return b"\r" # older 8-bit machines
None # no new line contained, cannot determine

def Exit(message:str = "") -> None: print("[EXIT]" + (" " + message + "." if message != "" else ""), file = sys.stderr); sys.exit(1)
def Exit(message:str = "", code = 1) -> None: print("[EXIT%s]" % (" %.1fs" % (time.time() - lateBinding.start) if lateBinding.verbose else "") + (" " + message + "." if message != "" else ""), file = sys.stderr); sys.exit(1)

def user_input(msg:str) -> str = input(msg) # referenceso __builtin__.raw_input on Python 2

Expand Down

0 comments on commit ec62d76

Please sign in to comment.