From e395e0825136830bbefa79d83f58221c5ccc2888 Mon Sep 17 00:00:00 2001 From: immensity Date: Mon, 3 Dec 2018 22:18:55 +0100 Subject: [PATCH] refactor main.py --- Pipfile | 14 +++ Pipfile.lock | 176 +++++++++++++++++++++++++++ README.md | 129 ++++++++------------ build/lib/pygit/main.py | 97 ++++----------- build/lib/pygit/test.py | 6 +- dist/python-git-4.0.tar.gz | Bin 14695 -> 0 bytes dist/python-git-4.1.tar.gz | Bin 0 -> 13303 bytes dist/python_git-4.0-py3-none-any.whl | Bin 10840 -> 0 bytes dist/python_git-4.1-py3-none-any.whl | Bin 0 -> 11173 bytes pygit/main.py | 97 ++++----------- pygit/test.py | 6 +- python_git.egg-info/PKG-INFO | 135 +++++++++----------- requirements.txt | 2 - setup.py | 72 +---------- shelves/index_shelf.bak | 0 shelves/index_shelf.dat | 0 shelves/index_shelf.dir | 0 shelves/name_shelf.bak | 0 shelves/name_shelf.dat | 0 shelves/name_shelf.dir | 0 20 files changed, 365 insertions(+), 369 deletions(-) create mode 100644 Pipfile create mode 100644 Pipfile.lock delete mode 100644 dist/python-git-4.0.tar.gz create mode 100644 dist/python-git-4.1.tar.gz delete mode 100644 dist/python_git-4.0-py3-none-any.whl create mode 100644 dist/python_git-4.1-py3-none-any.whl delete mode 100644 requirements.txt delete mode 100644 shelves/index_shelf.bak delete mode 100644 shelves/index_shelf.dat delete mode 100644 shelves/index_shelf.dir delete mode 100644 shelves/name_shelf.bak delete mode 100644 shelves/name_shelf.dat delete mode 100644 shelves/name_shelf.dir diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..9f1cbb4 --- /dev/null +++ b/Pipfile @@ -0,0 +1,14 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +coverage = "==4.5.1" +"send2trash" = "==1.5.0" + +[dev-packages] +twine = "*" + +[requires] +python_version = "3.6" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..3f0b38b --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,176 @@ +{ + "_meta": { + "hash": { + "sha256": "df3879b45ed476034aeb8ce3ced5324fdb58c2e64453b0a8d20d8727619a6ecb" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.6" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "coverage": { + "hashes": [ + "sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", + "sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", + "sha256:0bf8cbbd71adfff0ef1f3a1531e6402d13b7b01ac50a79c97ca15f030dba6306", + "sha256:10a46017fef60e16694a30627319f38a2b9b52e90182dddb6e37dcdab0f4bf95", + "sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", + "sha256:23d341cdd4a0371820eb2b0bd6b88f5003a7438bbedb33688cd33b8eae59affd", + "sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162", + "sha256:2a5b73210bad5279ddb558d9a2bfedc7f4bf6ad7f3c988641d83c40293deaec1", + "sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508", + "sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249", + "sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694", + "sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a", + "sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287", + "sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1", + "sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000", + "sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1", + "sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e", + "sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5", + "sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062", + "sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba", + "sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc", + "sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc", + "sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99", + "sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653", + "sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c", + "sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558", + "sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f", + "sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9", + "sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", + "sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", + "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", + "sha256:f05a636b4564104120111800021a92e43397bc12a5c72fed7036be8556e0029e", + "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80" + ], + "index": "pypi", + "version": "==4.5.1" + }, + "send2trash": { + "hashes": [ + "sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2", + "sha256:f1691922577b6fa12821234aeb57599d887c4900b9ca537948d2dac34aea888b" + ], + "index": "pypi", + "version": "==1.5.0" + } + }, + "develop": { + "bleach": { + "hashes": [ + "sha256:48d39675b80a75f6d1c3bdbffec791cf0bbbab665cf01e20da701c77de278718", + "sha256:73d26f018af5d5adcdabf5c1c974add4361a9c76af215fe32fdec8a6fc5fb9b9" + ], + "version": "==3.0.2" + }, + "certifi": { + "hashes": [ + "sha256:47f9c83ef4c0c621eaef743f133f09fa8a74a9b75f037e8624f83bd1b6626cb7", + "sha256:993f830721089fef441cdfeb4b2c8c9df86f0c63239f06bd025a76a7daddb033" + ], + "version": "==2018.11.29" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "docutils": { + "hashes": [ + "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6", + "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274", + "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6" + ], + "version": "==0.14" + }, + "idna": { + "hashes": [ + "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", + "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + ], + "version": "==2.7" + }, + "pkginfo": { + "hashes": [ + "sha256:5878d542a4b3f237e359926384f1dde4e099c9f5525d236b1840cf704fa8d474", + "sha256:a39076cb3eb34c333a0dd390b568e9e1e881c7bf2cc0aee12120636816f55aee" + ], + "version": "==1.4.2" + }, + "pygments": { + "hashes": [ + "sha256:6301ecb0997a52d2d31385e62d0a4a4cf18d2f2da7054a5ddad5c366cd39cee7", + "sha256:82666aac15622bd7bb685a4ee7f6625dd716da3ef7473620c192c0168aae64fc" + ], + "version": "==2.3.0" + }, + "readme-renderer": { + "hashes": [ + "sha256:bb16f55b259f27f75f640acf5e00cf897845a8b3e4731b5c1a436e4b8529202f", + "sha256:c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d" + ], + "version": "==24.0" + }, + "requests": { + "hashes": [ + "sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54", + "sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263" + ], + "version": "==2.20.1" + }, + "requests-toolbelt": { + "hashes": [ + "sha256:42c9c170abc2cacb78b8ab23ac957945c7716249206f90874651971a4acff237", + "sha256:f6a531936c6fa4c6cfce1b9c10d5c4f498d16528d2a54a22ca00011205a187b5" + ], + "version": "==0.8.0" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + }, + "tqdm": { + "hashes": [ + "sha256:3c4d4a5a41ef162dd61f1edb86b0e1c7859054ab656b2e7c7b77e7fbf6d9f392", + "sha256:5b4d5549984503050883bc126280b386f5f4ca87e6c023c5d015655ad75bdebb" + ], + "version": "==4.28.1" + }, + "twine": { + "hashes": [ + "sha256:7d89bc6acafb31d124e6e5b295ef26ac77030bf098960c2a4c4e058335827c5c", + "sha256:fad6f1251195f7ddd1460cb76d6ea106c93adb4e56c41e0da79658e56e547d2c" + ], + "index": "pypi", + "version": "==1.12.1" + }, + "urllib3": { + "hashes": [ + "sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39", + "sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22" + ], + "version": "==1.24.1" + }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" + ], + "version": "==0.5.1" + } + } +} diff --git a/README.md b/README.md index 0752bb2..9d5cd1a 100644 --- a/README.md +++ b/README.md @@ -24,139 +24,116 @@ Just unzip it and place it somewhere on your disk. Later (during initialization) ## Installation +```python + `pip install https://codeload.github.com/immensity/python-git/zip/master` `pip install python-git --upgrade` +``` -## Usage +## Initial setup -Upon successful installation, the below command should return a blank screen +1. To setup, you need to look for where `pygit` is installed in your system. If you're using anaconda it would likely be in `C:\ProgramData\Anaconda3\Lib\site-packages\pygit`. then issue the command - import pygit + `$ python \main.py`. -To use `python-git`, you have to tell it exactly two things, depending on your system setup. + For finding files in your system I recommend [everything](https://www.voidtools.com/) -1. The location of your `git` repositories. You may do this by passing it a list of strings on the command line. -Each string represents a full path name to single directory. You may also just provide a single directory which holds -multiple git repositories and `pygit` will grab all the repositories for your. +## Usage -1. The location of a `git` executable. This only applies if `git` is not accessible from your system `cmd`. That is, `git` is -2. not in your system path. More on this below. +1. Activate python environment on command line. -If you have a master directory that holds multiple `git` repositories, `pygit` can also take the full path name of this master directory -and then index the git repositories it finds there. It won't index those directories that are not git repos. + `import pygit # should return nothing if all goes well` -It is also possible to tell `pygit` not to index certain directories by specifying the starting string of the directory name. This is referred -to s a `rule`. Directories matching such rules will not be touched. +1. Now you need to specify exactly two things: -To initialize `pygit`, run + 1. where your git repos are + 1. where your `git-cmd.exe` is located. - pygit.initialize() +1. The location of your `git` repositories. You may do this by passing it a list of strings on the command line. Each string represents a full path name to single directory. You may also just provide a single directory which holds multiple git repositories and `pygit` will grab all the repositories for your. If you have a master directory that holds multiple `git` repositories, `pygit` can also take the full path name of this master directory and then index the git repositories it finds there. It won't index those directories that are not git repos. It is also possible to tell `pygit` not to index certain directories by specifying the starting string of the directory name. This is referred to as a `rule`. Directories matching such rules will not be touched. +1. The location of a `git-cmd.exe` executable. This only applies if `git` is not accessible from your system `cmd`. That is, `git` is not in your system path. More on this below. In case things change (perhaps you moved folders around) and you want to reset your folders, -just run the `set_all()` command again +just redo the initialization step +To see all available repositories run -To see all available repositories run :: + `pygit.show_repos()` - pygit.show_repos() +This command shows a list of all available repositories in the format -This command shows a list of all available repositories in the format :: + `repository_id: repository_name: repository_directory_path` - repository_id: repository_name: repository_directory_path +To load a particular repository use -To load a particular repository use :: + `pygit.load(repo_id_or_name)` - pygit.load(repo_id_or_name) +where `repo_id` is a string-valued id assigned to that particular repo. The first value in the `show_repos` command's output. -where **repo_id** is a string-valued id assigned to that particular repo. The first value in the `show_repos` command's output. +The `load\(\)` command returns a `Commands` object for that repo, which provides a gateway for issuing git commands on the repository +Operations that can be performed on `Commands` object are shown below. -The **load\(\)** command returns a `Commands` object for that repo, which provides a gateway for issuing git commands on the repository - -Operations that can be performed on `Commands` object are shown below. :: - - Commands().fetch() # perform fetch. +```python + Commands().fetch() # perform fetch Commands().status() # see status - Commands().add_all() # stage all changes for commit - Commands().commit(message='minor changes') # commit changes. Press enter to accept default message - Commands().push() # perform push action - Commands().pull() # perform pull request - Commands().add_commit() # add and commit at once - - +``` ### Batch Operations -Pygit provides some functions for performing batch operations on your repositories. :: +Pygit provides some functions for performing batch operations on your repositories. - pygit.load_multiple(*args) + `pygit.load_multiple(*args)` loads a set of repositories. You could decide to only load only 2 of 10 repositories. Perhaps you need to perform similar actions on those two alone. As an example - pygit.load_set("2", "5") + `pygit.load_set("2", "5")` -returns a `generator` of `Commands` objects for repositories 2 and 5. Afterwards you can use a :py:func:`for` loop to iterate over the repos -like below +returns a `generator` of `Commands` objects for repositories 2 and 5. Afterwards you can iterate over the repos like below +```python for each in pygit.load_set("2", "5"): each.add_commit() +``` - pygit.all_status() + `pygit.all_status()` -performs a **status** command on all your repositories. The result is written to a text file. The text file opens automatically. +performs a `status` command on all your repositories. The result is written to a text file. The text file opens automatically. The name of the file shows the date and time of the status request. All batch status request is written to its a separate file. Call it a snapshot of your repo status if you will -Those items which are out of sync with their remote counterpart (by being ahead or being behind) are also highlighted as needing attention. :: +Those items which are out of sync with their remote counterpart (by being ahead or being behind) are also highlighted as needing attention. - pygit.pull_all() + `pygit.pull_all()` +performs a `pull` request on all your repositories at once. Its `return` value is None. -performs a **pull** request on all your repositories at once. Its `return` value is None. :: + `pygit.push_all()` - pygit.push_all() +performs a `push` action on all your repositories at once. Its `return` value is None. - -performs a **push** action on all your repositories at once. Its `return` value is None. :: - - pygit.load_all() + `pygit.load_all()` returns a `generator` of `Commands` object for every repository. ## To do -Add **git-bash.exe** - -Implement Commands.branch() - -Write tests - -Run test after importation to make sure every other thing works fine. - -Define an update function that updates the repo dictionaries for the case when a new repo is added but the overall directory structure remains unchanged. - -Git search pathsep - -git check locations - -C:\Program Files\Git\cmd\git.exe -C:\Program Files (x86)\Git\cmd\git.exe -C:\Program Files\Git\cmd\git.exe -C:\Users\Chidimma\AppData\Local\Programs\Git\cmd\git.exe - -https://stackoverflow.com/questions/19687394/python-script-to-determine-if-a-directory-is-a-git-repository - -http://gitpython.readthedocs.io/en/stable/ - -https://simpleisbetterthancomplex.com/tips/2017/08/11/django-tip-21-redirects-app.html +1. Refactor `initialize()` function +1. Add `git-bash.exe` +1. Implement `Commands.branch()` +1. Refactor tests +1. Auto-run test after importation to make sure every other thing works fine. +1. Define an update function that updates the repo dictionaries for the case when a new repo is added but the overall directory structure remains unchanged. -https://simpleisbetterthancomplex.com/tutorial/2017/08/20/how-to-use-celery-with-django.html +## Update git check locations -https://realpython.com/asynchronous-tasks-with-django-and-celery/ +1. C:\Program Files\Git\cmd\git.exe +1. C:\Program Files (x86)\Git\cmd\git.exe +1. C:\Program Files\Git\cmd\git.exe +1. C:\Users\Chidimma\AppData\Local\Programs\Git\cmd\git.exe diff --git a/build/lib/pygit/main.py b/build/lib/pygit/main.py index ebc60af..8f3c808 100644 --- a/build/lib/pygit/main.py +++ b/build/lib/pygit/main.py @@ -5,66 +5,21 @@ import shutil import shelve import argparse + +from pathlib import Path from datetime import datetime from subprocess import Popen, PIPE, STDOUT from send2trash import send2trash -USERHOME = os.path.abspath(os.path.expanduser('~')) -DESKTOP = os.path.abspath(USERHOME + '/Desktop/') - -STATUS_DIR = os.path.join(DESKTOP ,"status") -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -SHELF_DIR = os.path.join(BASE_DIR, "shelves") -TEST_DIR = os.path.join(BASE_DIR, "test_git/") -TIMING = datetime.now().strftime("%a_%d_%b_%Y_%H_%M_%S_%p") +USERHOME = Path.home() +DESKTOP = USERHOME / 'Desktop' +STATUS_DIR = DESKTOP / "status" +BASE_DIR = Path().resolve() +SHELF_DIR = Path.joinpath(BASE_DIR, "shelf-dir") +TEST_DIR = Path.joinpath(BASE_DIR, "test-dir") +TIME_STAMP = datetime.now().strftime("%a_%d_%b_%Y_%H_%M_%S_%p") -def get_site_packages_directory(): - """Returns site packages directory""" - # try iterating over sys.path - try: - return next(p for p in sys.path if 'site-packages' in p) - except StopIteration: - pass - - # try manually constructing the path and check if it exists - py_version = '{}.{}'.format(sys.version_info[0], sys.version_info[1]) - - prefix_paths = [ - sys.prefix + '/lib/python{}/dist-packages/', - sys.prefix + '/lib/python{}/site-packages/', - sys.prefix + '/local/lib/python{}/dist-packages/', - sys.prefix + '/local/lib/python{}/site-packages/', - '/Library/Python/{}/site-packages/', - ] - - py_installation_paths = [each.format(py_version) for each in prefix_paths] - paths = py_installation_paths + [ - # these paths for versionless installs like jupyter - sys.prefix + '/lib/dist-packages/', - sys.prefix + '/lib/site-packages/', - sys.prefix + '/local/lib/dist-packages/', - sys.prefix + '/local/lib/site-packages/', - ] - for path in paths: - if os.path.exists(path): - return path - return None - -def show_help(): - """How to call the initialization program""" - site_package_directory = get_site_packages_directory() - source_directory_1 = '{}/pygit/main.py'.format(site_package_directory) - source_directory_2 = '{}/python_git-4.0-py3.6.egg/pygit/main.py'.format(site_package_directory) - print('\n\nTo initialize pygit, run\n') - if os.path.exists(source_directory_1): - print('\tpython ', source_directory_1) - elif os.path.exists(source_directory_2): - print('\tpython ', source_directory_2) - else: - print("Installation not found") - print("Include the -h flag for help") - return def clear_screen(): if sys.platform == 'win32': @@ -138,13 +93,13 @@ def initialize(): Accepts command line inputs only. """ try: - os.mkdir(SHELF_DIR) + Path.mkdir(SHELF_DIR) except FileExistsError: shutil.rmtree(SHELF_DIR) - os.mkdir(SHELF_DIR) + Path.mkdir(SHELF_DIR) - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) - index_shelf = shelve.open(os.path.join(SHELF_DIR, "index_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) + index_shelf = shelve.open(Path.joinpath(SHELF_DIR, "index_shelf")) parser = argparse.ArgumentParser(prog="Pygit. Initialize pygit's working directories.") parser.add_argument("-v", "--verbosity", type=int, help="turn verbosity ON/OFF", choices=[0,1]) @@ -190,7 +145,7 @@ def initialize(): folder_paths = [ name for name in os.listdir(args.masterDirectory) \ - if os.path.isdir(os.path.join(args.masterDirectory, name)) + if os.path.isdir(Path.joinpath(args.masterDirectory, name)) ] for name in folder_paths: @@ -199,7 +154,7 @@ def initialize(): if args.verbosity: print(name, " starts with one of ", bad_folder_starts, " skipping\n") continue - path = os.path.join(args.masterDirectory, name) + path = Path.joinpath(args.masterDirectory, name) if args.rules: # if any of the string patterns is found in path name, that folder will be skipped. if any([rule in path for rule in args.rules]): @@ -256,8 +211,8 @@ def initialize(): if args.verbosity: print("\nDone.\nThe following directories were set.\n") - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) - index_shelf = shelve.open(os.path.join(SHELF_DIR, "index_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) + index_shelf = shelve.open(Path.joinpath(SHELF_DIR, "index_shelf")) print("{:<4} {:<20} {:<}".format("Key", "| Name", "| Path")) print("*********************************") @@ -422,8 +377,8 @@ def show_repos(): """Show all available repositories, path, and unique ID""" clear_screen() print("\nThe following repos are available.\n") - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) - index_shelf = shelve.open(os.path.join(SHELF_DIR, "index_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) + index_shelf = shelve.open(Path.joinpath(SHELF_DIR, "index_shelf")) print("{:<4} {:<20} {:<}".format("Key", "| Name", "| Path")) print("******************************************") @@ -435,8 +390,8 @@ def show_repos(): def load(input_string): # id is string """Load a repository with specified id""" - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) - index_shelf = shelve.open(os.path.join(SHELF_DIR, "index_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) + index_shelf = shelve.open(Path.joinpath(SHELF_DIR, "index_shelf")) input_string = str(input_string) try: @@ -470,7 +425,7 @@ def load_multiple(*args, _all=False): """ if _all: - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) for key in name_shelf.keys(): yield load(key) else: @@ -500,19 +455,19 @@ def all_status(status_dir=STATUS_DIR): attention = [] try: - os.mkdir(DESKTOP) + Path.mkdir(DESKTOP) except FileExistsError: pass try: - os.mkdir(status_dir) + Path.mkdir(status_dir) except FileExistsError: pass os.chdir(status_dir) - fname = "REPO_STATUS_@_{}.md".format(TIMING) + fname = "REPO_STATUS_@_{}.md".format(TIME_STAMP) with open(fname, 'w+') as fhand: - fhand.write("# Repository status as at {}".format(TIMING)) + fhand.write("# Repository status as at {}".format(TIME_STAMP)) fhand.write("\n\n") for each in load_multiple(_all=True): name = each.name diff --git a/build/lib/pygit/test.py b/build/lib/pygit/test.py index 96fe65f..587b03e 100644 --- a/build/lib/pygit/test.py +++ b/build/lib/pygit/test.py @@ -4,6 +4,8 @@ import os import random import unittest + +from pathlib import Path from glob import glob from random import choice from send2trash import send2trash @@ -19,12 +21,12 @@ class TestAppSetupA(unittest.TestCase): """Basic setup to test API""" def setUp(self): """Setup""" - print("Start ", os.path.basename(__file__), " tests") + print("Start ", Path().resolve(), " tests") initialize() def test_ids_exist(self): # always regen for this test to work """Test id file created and that its content is a dictionary""" - assert os.path.exists(IDS) + assert Path(IDS).exists() with open(IDS) as rhand: self.assertIsInstance(json.load(rhand), dict) diff --git a/dist/python-git-4.0.tar.gz b/dist/python-git-4.0.tar.gz deleted file mode 100644 index 5db0c284d563aad0d1cc3491dd2ae7c32a74835c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14695 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 z 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 diff --git a/dist/python_git-4.1-py3-none-any.whl b/dist/python_git-4.1-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..90bea8c78a71e83b2d2310087bfa555cfaaec3a0 GIT binary patch literal 11173 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 F`aco`p=SU9 literal 0 HcmV?d00001 diff --git a/pygit/main.py b/pygit/main.py index ebc60af..8f3c808 100644 --- a/pygit/main.py +++ b/pygit/main.py @@ -5,66 +5,21 @@ import shutil import shelve import argparse + +from pathlib import Path from datetime import datetime from subprocess import Popen, PIPE, STDOUT from send2trash import send2trash -USERHOME = os.path.abspath(os.path.expanduser('~')) -DESKTOP = os.path.abspath(USERHOME + '/Desktop/') - -STATUS_DIR = os.path.join(DESKTOP ,"status") -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -SHELF_DIR = os.path.join(BASE_DIR, "shelves") -TEST_DIR = os.path.join(BASE_DIR, "test_git/") -TIMING = datetime.now().strftime("%a_%d_%b_%Y_%H_%M_%S_%p") +USERHOME = Path.home() +DESKTOP = USERHOME / 'Desktop' +STATUS_DIR = DESKTOP / "status" +BASE_DIR = Path().resolve() +SHELF_DIR = Path.joinpath(BASE_DIR, "shelf-dir") +TEST_DIR = Path.joinpath(BASE_DIR, "test-dir") +TIME_STAMP = datetime.now().strftime("%a_%d_%b_%Y_%H_%M_%S_%p") -def get_site_packages_directory(): - """Returns site packages directory""" - # try iterating over sys.path - try: - return next(p for p in sys.path if 'site-packages' in p) - except StopIteration: - pass - - # try manually constructing the path and check if it exists - py_version = '{}.{}'.format(sys.version_info[0], sys.version_info[1]) - - prefix_paths = [ - sys.prefix + '/lib/python{}/dist-packages/', - sys.prefix + '/lib/python{}/site-packages/', - sys.prefix + '/local/lib/python{}/dist-packages/', - sys.prefix + '/local/lib/python{}/site-packages/', - '/Library/Python/{}/site-packages/', - ] - - py_installation_paths = [each.format(py_version) for each in prefix_paths] - paths = py_installation_paths + [ - # these paths for versionless installs like jupyter - sys.prefix + '/lib/dist-packages/', - sys.prefix + '/lib/site-packages/', - sys.prefix + '/local/lib/dist-packages/', - sys.prefix + '/local/lib/site-packages/', - ] - for path in paths: - if os.path.exists(path): - return path - return None - -def show_help(): - """How to call the initialization program""" - site_package_directory = get_site_packages_directory() - source_directory_1 = '{}/pygit/main.py'.format(site_package_directory) - source_directory_2 = '{}/python_git-4.0-py3.6.egg/pygit/main.py'.format(site_package_directory) - print('\n\nTo initialize pygit, run\n') - if os.path.exists(source_directory_1): - print('\tpython ', source_directory_1) - elif os.path.exists(source_directory_2): - print('\tpython ', source_directory_2) - else: - print("Installation not found") - print("Include the -h flag for help") - return def clear_screen(): if sys.platform == 'win32': @@ -138,13 +93,13 @@ def initialize(): Accepts command line inputs only. """ try: - os.mkdir(SHELF_DIR) + Path.mkdir(SHELF_DIR) except FileExistsError: shutil.rmtree(SHELF_DIR) - os.mkdir(SHELF_DIR) + Path.mkdir(SHELF_DIR) - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) - index_shelf = shelve.open(os.path.join(SHELF_DIR, "index_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) + index_shelf = shelve.open(Path.joinpath(SHELF_DIR, "index_shelf")) parser = argparse.ArgumentParser(prog="Pygit. Initialize pygit's working directories.") parser.add_argument("-v", "--verbosity", type=int, help="turn verbosity ON/OFF", choices=[0,1]) @@ -190,7 +145,7 @@ def initialize(): folder_paths = [ name for name in os.listdir(args.masterDirectory) \ - if os.path.isdir(os.path.join(args.masterDirectory, name)) + if os.path.isdir(Path.joinpath(args.masterDirectory, name)) ] for name in folder_paths: @@ -199,7 +154,7 @@ def initialize(): if args.verbosity: print(name, " starts with one of ", bad_folder_starts, " skipping\n") continue - path = os.path.join(args.masterDirectory, name) + path = Path.joinpath(args.masterDirectory, name) if args.rules: # if any of the string patterns is found in path name, that folder will be skipped. if any([rule in path for rule in args.rules]): @@ -256,8 +211,8 @@ def initialize(): if args.verbosity: print("\nDone.\nThe following directories were set.\n") - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) - index_shelf = shelve.open(os.path.join(SHELF_DIR, "index_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) + index_shelf = shelve.open(Path.joinpath(SHELF_DIR, "index_shelf")) print("{:<4} {:<20} {:<}".format("Key", "| Name", "| Path")) print("*********************************") @@ -422,8 +377,8 @@ def show_repos(): """Show all available repositories, path, and unique ID""" clear_screen() print("\nThe following repos are available.\n") - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) - index_shelf = shelve.open(os.path.join(SHELF_DIR, "index_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) + index_shelf = shelve.open(Path.joinpath(SHELF_DIR, "index_shelf")) print("{:<4} {:<20} {:<}".format("Key", "| Name", "| Path")) print("******************************************") @@ -435,8 +390,8 @@ def show_repos(): def load(input_string): # id is string """Load a repository with specified id""" - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) - index_shelf = shelve.open(os.path.join(SHELF_DIR, "index_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) + index_shelf = shelve.open(Path.joinpath(SHELF_DIR, "index_shelf")) input_string = str(input_string) try: @@ -470,7 +425,7 @@ def load_multiple(*args, _all=False): """ if _all: - name_shelf = shelve.open(os.path.join(SHELF_DIR, "name_shelf")) + name_shelf = shelve.open(Path.joinpath(SHELF_DIR, "name_shelf")) for key in name_shelf.keys(): yield load(key) else: @@ -500,19 +455,19 @@ def all_status(status_dir=STATUS_DIR): attention = [] try: - os.mkdir(DESKTOP) + Path.mkdir(DESKTOP) except FileExistsError: pass try: - os.mkdir(status_dir) + Path.mkdir(status_dir) except FileExistsError: pass os.chdir(status_dir) - fname = "REPO_STATUS_@_{}.md".format(TIMING) + fname = "REPO_STATUS_@_{}.md".format(TIME_STAMP) with open(fname, 'w+') as fhand: - fhand.write("# Repository status as at {}".format(TIMING)) + fhand.write("# Repository status as at {}".format(TIME_STAMP)) fhand.write("\n\n") for each in load_multiple(_all=True): name = each.name diff --git a/pygit/test.py b/pygit/test.py index 96fe65f..587b03e 100644 --- a/pygit/test.py +++ b/pygit/test.py @@ -4,6 +4,8 @@ import os import random import unittest + +from pathlib import Path from glob import glob from random import choice from send2trash import send2trash @@ -19,12 +21,12 @@ class TestAppSetupA(unittest.TestCase): """Basic setup to test API""" def setUp(self): """Setup""" - print("Start ", os.path.basename(__file__), " tests") + print("Start ", Path().resolve(), " tests") initialize() def test_ids_exist(self): # always regen for this test to work """Test id file created and that its content is a dictionary""" - assert os.path.exists(IDS) + assert Path(IDS).exists() with open(IDS) as rhand: self.assertIsInstance(json.load(rhand), dict) diff --git a/python_git.egg-info/PKG-INFO b/python_git.egg-info/PKG-INFO index 673a828..df7a12c 100644 --- a/python_git.egg-info/PKG-INFO +++ b/python_git.egg-info/PKG-INFO @@ -1,12 +1,12 @@ Metadata-Version: 1.1 Name: python-git -Version: 4.0 +Version: 4.1 Summary: Automate boring git tasks -Home-page: https://github.com/immensity/pygit +Home-page: https://github.com/chidimo/python-git Author: Chidi Orji Author-email: orjichidi95@gmail.com License: MIT -Download-URL: https://codeload.github.com/immensity/python-git/zip/master +Download-URL: https://github.com/chidimo/python-git/archive/master.zip Description: # python-git Automate the boring git stuff with python @@ -33,142 +33,119 @@ Description: # python-git ## Installation + ```python + `pip install https://codeload.github.com/immensity/python-git/zip/master` `pip install python-git --upgrade` + ``` - ## Usage + ## Initial setup - Upon successful installation, the below command should return a blank screen + 1. To setup, you need to look for where `pygit` is installed in your system. If you're using anaconda it would likely be in `C:\ProgramData\Anaconda3\Lib\site-packages\pygit`. then issue the command - import pygit + `$ python \main.py`. - To use `python-git`, you have to tell it exactly two things, depending on your system setup. + For finding files in your system I recommend [everything](https://www.voidtools.com/) - 1. The location of your `git` repositories. You may do this by passing it a list of strings on the command line. - Each string represents a full path name to single directory. You may also just provide a single directory which holds - multiple git repositories and `pygit` will grab all the repositories for your. + ## Usage - 1. The location of a `git` executable. This only applies if `git` is not accessible from your system `cmd`. That is, `git` is - 2. not in your system path. More on this below. + 1. Activate python environment on command line. - If you have a master directory that holds multiple `git` repositories, `pygit` can also take the full path name of this master directory - and then index the git repositories it finds there. It won't index those directories that are not git repos. + `import pygit # should return nothing if all goes well` - It is also possible to tell `pygit` not to index certain directories by specifying the starting string of the directory name. This is referred - to s a `rule`. Directories matching such rules will not be touched. + 1. Now you need to specify exactly two things: - To initialize `pygit`, run + 1. where your git repos are + 1. where your `git-cmd.exe` is located. - pygit.initialize() + 1. The location of your `git` repositories. You may do this by passing it a list of strings on the command line. Each string represents a full path name to single directory. You may also just provide a single directory which holds multiple git repositories and `pygit` will grab all the repositories for your. If you have a master directory that holds multiple `git` repositories, `pygit` can also take the full path name of this master directory and then index the git repositories it finds there. It won't index those directories that are not git repos. It is also possible to tell `pygit` not to index certain directories by specifying the starting string of the directory name. This is referred to as a `rule`. Directories matching such rules will not be touched. + 1. The location of a `git-cmd.exe` executable. This only applies if `git` is not accessible from your system `cmd`. That is, `git` is not in your system path. More on this below. In case things change (perhaps you moved folders around) and you want to reset your folders, - just run the `set_all()` command again + just redo the initialization step + To see all available repositories run - To see all available repositories run :: + `pygit.show_repos()` - pygit.show_repos() + This command shows a list of all available repositories in the format - This command shows a list of all available repositories in the format :: + `repository_id: repository_name: repository_directory_path` - repository_id: repository_name: repository_directory_path + To load a particular repository use - To load a particular repository use :: + `pygit.load(repo_id_or_name)` - pygit.load(repo_id_or_name) + where `repo_id` is a string-valued id assigned to that particular repo. The first value in the `show_repos` command's output. - where **repo_id** is a string-valued id assigned to that particular repo. The first value in the `show_repos` command's output. + The `load\(\)` command returns a `Commands` object for that repo, which provides a gateway for issuing git commands on the repository + Operations that can be performed on `Commands` object are shown below. - The **load\(\)** command returns a `Commands` object for that repo, which provides a gateway for issuing git commands on the repository - - Operations that can be performed on `Commands` object are shown below. :: - - Commands().fetch() # perform fetch. + ```python + Commands().fetch() # perform fetch Commands().status() # see status - Commands().add_all() # stage all changes for commit - Commands().commit(message='minor changes') # commit changes. Press enter to accept default message - Commands().push() # perform push action - Commands().pull() # perform pull request - Commands().add_commit() # add and commit at once - - + ``` ### Batch Operations - Pygit provides some functions for performing batch operations on your repositories. :: + Pygit provides some functions for performing batch operations on your repositories. - pygit.load_multiple(*args) + `pygit.load_multiple(*args)` loads a set of repositories. You could decide to only load only 2 of 10 repositories. Perhaps you need to perform similar actions on those two alone. As an example - pygit.load_set("2", "5") + `pygit.load_set("2", "5")` - returns a `generator` of `Commands` objects for repositories 2 and 5. Afterwards you can use a :py:func:`for` loop to iterate over the repos - like below + returns a `generator` of `Commands` objects for repositories 2 and 5. Afterwards you can iterate over the repos like below + ```python for each in pygit.load_set("2", "5"): each.add_commit() + ``` - pygit.all_status() + `pygit.all_status()` - performs a **status** command on all your repositories. The result is written to a text file. The text file opens automatically. + performs a `status` command on all your repositories. The result is written to a text file. The text file opens automatically. The name of the file shows the date and time of the status request. All batch status request is written to its a separate file. Call it a snapshot of your repo status if you will - Those items which are out of sync with their remote counterpart (by being ahead or being behind) are also highlighted as needing attention. :: + Those items which are out of sync with their remote counterpart (by being ahead or being behind) are also highlighted as needing attention. - pygit.pull_all() + `pygit.pull_all()` + performs a `pull` request on all your repositories at once. Its `return` value is None. - performs a **pull** request on all your repositories at once. Its `return` value is None. :: + `pygit.push_all()` - pygit.push_all() + performs a `push` action on all your repositories at once. Its `return` value is None. - - performs a **push** action on all your repositories at once. Its `return` value is None. :: - - pygit.load_all() + `pygit.load_all()` returns a `generator` of `Commands` object for every repository. ## To do - Add **git-bash.exe** - - Implement Commands.branch() - - Write tests - - Run test after importation to make sure every other thing works fine. - - Define an update function that updates the repo dictionaries for the case when a new repo is added but the overall directory structure remains unchanged. - - Git search pathsep - - git check locations - - C:\Program Files\Git\cmd\git.exe - C:\Program Files (x86)\Git\cmd\git.exe - C:\Program Files\Git\cmd\git.exe - C:\Users\Chidimma\AppData\Local\Programs\Git\cmd\git.exe - - https://stackoverflow.com/questions/19687394/python-script-to-determine-if-a-directory-is-a-git-repository - - http://gitpython.readthedocs.io/en/stable/ - - https://simpleisbetterthancomplex.com/tips/2017/08/11/django-tip-21-redirects-app.html + 1. Refactor `initialize()` function + 1. Add `git-bash.exe` + 1. Implement `Commands.branch()` + 1. Refactor tests + 1. Auto-run test after importation to make sure every other thing works fine. + 1. Define an update function that updates the repo dictionaries for the case when a new repo is added but the overall directory structure remains unchanged. - https://simpleisbetterthancomplex.com/tutorial/2017/08/20/how-to-use-celery-with-django.html + ## Update git check locations - https://realpython.com/asynchronous-tasks-with-django-and-celery/ + 1. C:\Program Files\Git\cmd\git.exe + 1. C:\Program Files (x86)\Git\cmd\git.exe + 1. C:\Program Files\Git\cmd\git.exe + 1. C:\Users\Chidimma\AppData\Local\Programs\Git\cmd\git.exe Keywords: automate boring git and github tasks Platform: UNKNOWN diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 20056c3..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -coverage==4.5.1 -Send2Trash==1.5.0 diff --git a/setup.py b/setup.py index 0d4a96e..588939e 100644 --- a/setup.py +++ b/setup.py @@ -1,78 +1,22 @@ """Setup""" -# https://stackoverflow.com/questions/20288711/post-install-script-with-python-setuptools?rq=1 -# https://stackoverflow.com/questions/17806485/execute-a-python-script-post-install-using-distutils-setuptools -# https://pymotw.com/2/site/#module-sitecustomize -# https://stackoverflow.com/questions/136097/what-is-the-difference-between-staticmethod-and-classmethod-in-python?rq=1 -# https://www.programcreek.com/python/example/54257/site.USER_BASE import os import sys import site + +from pathlib import Path from subprocess import call from setuptools import setup -from setuptools.command.install import install as _install - -# def get_site_packages_directory(): -# """Returns site packages directory""" -# # try iterating over sys.path -# try: -# return next(p for p in sys.path if 'site-packages' in p) -# except StopIteration: -# pass - -# # try manually constructing the path and check if it exists -# py_version = '{}.{}'.format(sys.version_info[0], sys.version_info[1]) - -# prefix_paths = [ -# sys.prefix + '/lib/python{}/dist-packages/', -# sys.prefix + '/lib/python{}/site-packages/', -# sys.prefix + '/local/lib/python{}/dist-packages/', -# sys.prefix + '/local/lib/python{}/site-packages/', -# '/Library/Python/{}/site-packages/', -# ] - -# py_installation_paths = [each.format(py_version) for each in prefix_paths] -# paths = py_installation_paths + [ -# # these paths for versionless installs like jupyter -# sys.prefix + '/lib/dist-packages/', -# sys.prefix + '/lib/site-packages/', -# sys.prefix + '/local/lib/dist-packages/', -# sys.prefix + '/local/lib/site-packages/', -# ] -# for path in paths: -# if os.path.exists(path): -# return path -# return None -# def add_initialize_directory_to_system_path(install_directory): -# """Adds the initialize.py file to path""" -# if os.path.exists(install_directory): -# program_directory = '{}/pygit-3.0-py3.6.egg/pygit'.format(install_directory) -# print('\n\nTo initialize pygit, please run') -# print('\t', program_directory + '/initialize.py') -# print('with the appropriate command line arguments\n\n') -# else: -# print('Program directory, ', install_directory, ' is missing') -# return - -# def _post_install(dir): -# install_dir = get_site_packages_directory() -# add_initialize_directory_to_system_path(install_dir) - -# class install(_install): -# def run(self): -# print("USING CUSTOM INSTALLL") -# _install.run(self) -# self.execute(_post_install, (self.install_lib,), -# msg="Running post install task") def readme(): """Readme""" with open("README.md") as rhand: return rhand.read() + setup(name='python-git', - version='4.0', + version='4.1', description='Automate boring git tasks', long_description=readme(), classifiers=[ @@ -87,8 +31,8 @@ def readme(): 'Topic :: Utilities', ], keywords='automate boring git and github tasks', - url='https://github.com/immensity/pygit', - download_url='https://codeload.github.com/immensity/python-git/zip/master', + url='https://github.com/chidimo/python-git', + download_url='https://github.com/chidimo/python-git/archive/master.zip', author='Chidi Orji', author_email='orjichidi95@gmail.com', license='MIT', @@ -98,7 +42,3 @@ def readme(): ], zip_safe=False, test_suite='nose2.collector.collector',) - -# setup( -# cmdclass={'install': install}, -# ) diff --git a/shelves/index_shelf.bak b/shelves/index_shelf.bak deleted file mode 100644 index e69de29..0000000 diff --git a/shelves/index_shelf.dat b/shelves/index_shelf.dat deleted file mode 100644 index e69de29..0000000 diff --git a/shelves/index_shelf.dir b/shelves/index_shelf.dir deleted file mode 100644 index e69de29..0000000 diff --git a/shelves/name_shelf.bak b/shelves/name_shelf.bak deleted file mode 100644 index e69de29..0000000 diff --git a/shelves/name_shelf.dat b/shelves/name_shelf.dat deleted file mode 100644 index e69de29..0000000 diff --git a/shelves/name_shelf.dir b/shelves/name_shelf.dir deleted file mode 100644 index e69de29..0000000