Skip to content

Commit

Permalink
Release v1.2.0: Support for python3.5 fixed, auto detect args
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolaiSoeborg committed Jun 6, 2019
1 parent 4546f59 commit 6cc2a46
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 61 deletions.
88 changes: 87 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,90 @@ The advantages of ELF*2*deb is;

* can be installed using `pip install elf2deb` or used a as a standalone executable `./elf2deb.pyz`

* simple, small size (7 kB), and few dependencies (python3 and requests)
* simple, small size (< 10 kB), and few dependencies: `>= python3.5` (+ `requests` if need to download a license file)

## More examples (interactive!)

In version 1.2.0 a interactive menu was added to ELF*2*deb:

```bash
$ git clone https://github.com/NicolaiSoeborg/ELF2deb.git && cd ELF2deb/
$ make # to make 'elf2deb.pyz' (or use pip to install globally, or carry/copy elf2deb.pyz around)
$ ./elf2deb.pyz elf2deb.pyz # package 'elf2deb.pyz' using elf2deb (very meta!)
Package info:
author_mail: [email protected]
author_name: Nicolai Søborg
binary_files: ['elf2deb.pyz']
dependencies:
homepage: None
license: None
license_file: <_io.TextIOWrapper name='/.../ELF2deb/LICENSE' mode='r' encoding='UTF-8'>
license_holder: None
license_year: None
package_name: ELF2deb
package_version: 0.0.1
==> Does this look correct? (y/n/q): n

Properties:
[1] author_mail
[2] author_name
[3] binary_files
[4] dependencies
[5] homepage
[6] license
[7] license_file
[8] license_holder
[9] license_year
[10] package_name
[11] package_version
==> Which property to change? (1..11): 4
==> Which value should dependencies be changed to? python3, python3-requests

Package info:
author_mail: [email protected]
author_name: Nicolai Søborg
binary_files: ['elf2deb.pyz']
dependencies: python3, python3-requests
homepage: None
license: None
license_file: <_io.TextIOWrapper name='/home/nsq/pakker/test/ELF2deb/LICENSE' mode='r' encoding='UTF-8'>
license_holder: None
license_year: None
package_name: ELF2deb
package_version: 0.0.1
==> Does this look correct? (y/n/q): n
[...]
==> Which value should package_version be changed to? 1.2.0
[...]
==> Does this look correct? (y/n/q): y
Copying templates... done!
Copying files... done!
Run:
* cd elf2deb-1.2.0
* vim debian/control # change description, dont add empty lines
* debuild -us -uc # remove -us -uc if you want to sign the deb file

$ cd elf2deb-1.2.0
$ vim debian/control
$ debuild -us -uc
[...]
dpkg-deb: building package 'elf2deb' in '../elf2deb_1.2.0_amd64.deb'.

$ dpkg-deb --info ../elf2deb_1.2.0_amd64.deb
new Debian package, version 2.0.
size 5100 bytes: control archive=624 bytes.
383 bytes, 12 lines control
189 bytes, 3 lines md5sums
Package: elf2deb
Version: 1.2.0
Architecture: amd64
Maintainer: Nicolai Søborg <[email protected]>
Installed-Size: 20
Depends: python3, python3-requests
Section: misc
Priority: optional
Multi-Arch: foreign
Description: tool to easily package any binary to a deb file
ELF2deb makes it easy to package simple binaries to a deb file
to help deploy files across debian environments.
```
180 changes: 120 additions & 60 deletions elf2deb/__main__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,74 @@
import argparse
import os
import shutil
from subprocess import run, DEVNULL
from pathlib import Path
from zipfile import ZipFile

__version__ = "1.1.0"
__version__ = "1.2.0"
TEMPLATE_DIR = "templates/"

def main():
args = get_args()

# Create app dir:
package_dir = Path("{package_name}-{package_version}".format(**vars(args)))
if package_dir.exists():
if (input("Folder {} already exists. Delete? (y/n) ".format(package_dir)).lower() == "y"):
shutil.rmtree(str(package_dir))
package_dir.mkdir(exist_ok=True)

print("Copying templates... ", end='', flush=True)
try:
# If running from a .pyz file:
me = ZipFile(os.path.dirname(__file__), "r")
except:
# If running from pip:
me = ZipFile(os.path.dirname(__file__) + '/elf2deb.pyz' , "r")
for template in me.filelist:
if template.filename.startswith("__"):
continue # skip dunder files

target_filename = template.filename[len(TEMPLATE_DIR):]
if template.filename.endswith('/'):
(package_dir / target_filename).mkdir(exist_ok=True)
else:
data = me.read(template).decode().format(**vars(args))
(package_dir / target_filename).write_text(data)

if args.license is not None:
copyright_file = package_dir / 'debian/copyright'
copyright_file.write_text(get_copyright(args))
elif args.license_file is not None:
copyright_file = package_dir / 'debian/copyright'
copyright_file.write_text(args.license_file.read())

# Make debian/rules executable:
mode = os.stat(str(package_dir / 'debian/rules')).st_mode
mode |= (mode & 0o444) >> 2 # copy R bits to X
os.chmod(str(package_dir / 'debian/rules'), mode)
print("done!")

print("Copying files... ", end='', flush=True)
makefile = open(str(package_dir / 'Makefile'), 'at')
for i, binary in enumerate(args.binary_files):
# Copy binary to package base dir:
shutil.copy(binary, str(package_dir / os.path.basename(binary)))
if i > 0:
# Update makefile (TODO: update template to support a list of binaries)
makefile.write('\tcp {} $(DESTDIR)$(PREFIX)/bin/\n'.format(binary))
makefile.close()
print("done!")

run(['dch', '--create', '--empty', '--distribution', 'unstable', '--package', args.package_name, '--newversion', args.package_version], cwd=str(package_dir))
run(['dch', '--append', 'Packaged using ELF2deb v{}'.format(__version__)], stderr=DEVNULL, cwd=str(package_dir))

print("Run:")
print(" * cd {}".format(package_dir))
print(" * vim debian/control # change description, dont add empty lines")
print(" * debuild -us -uc # remove -us -uc if you want to sign the deb file")


def get_copyright(args):
import requests
from datetime import datetime
Expand Down Expand Up @@ -36,8 +98,44 @@ def get_copyright(args):
return license_txt


def main():
import argparse
def auto_config():
config = {}

# Check if a "LICENSE" file is in cwd:
for f in filter(lambda x: x.is_file(), Path.cwd().iterdir()):
if "LICENSE" in f.name.upper():
config['license_file'] = f

args_required = not ('license_file' in config)
return args_required, config


def verify_auto_config(args):
while True:
items = sorted(vars(args).items())
print("Package info:")
for k, v in items:
print('{}: {}'.format(k, v))
ans = input("==> Does this look correct? (y/n/q) ").lower()
if ans == 'y':
return args
elif ans == 'n':
print("\nProperties:")
for i, (k, _) in enumerate(items):
print('[{}] {}'.format(i+1, k))
while True:
change_idx = int(input("\n==> Which property to change? ({}..{}) ".format(1, len(items)))) - 1
if 0 <= change_idx < len(items):
break
prop = items[change_idx][0]
new_value = input("==> Which value should {} be changed to? ".format(prop))
args.__dict__[prop] = new_value # change args
elif ans == 'q':
exit(1)


def get_args():
args_required, config = auto_config()

parser = argparse.ArgumentParser(prog="ELF2deb")
parser.add_argument(
Expand All @@ -46,13 +144,13 @@ def main():

package_group = parser.add_argument_group("package info")
package_group.add_argument(
"--package_name", required=True, help="The name of the deb package"
"--package_name", required=args_required, help="The name of the deb package"
)
package_group.add_argument(
"--package_version", required=True, help="The version of the package"
"--package_version", required=args_required, help="The version of the package"
)
package_group.add_argument(
"--homepage", help="The webpage of the package"
"--homepage", "--webpage", help="The webpage of the package"
)
package_group.add_argument(
"--dependencies", default="", help="Dependencies specified in the deb package (comma seperated)"
Expand Down Expand Up @@ -80,64 +178,26 @@ def main():
"binary_files", help="The binaries you want to package.", nargs="+"
)

# Parse arguments:
args = parser.parse_args()

args.author_name = os.getenv("DEBFULLNAME")
args.author_mail = os.getenv("DEBEMAIL")
args.author_name = os.getenv("DEBFULLNAME", os.getlogin())
args.author_mail = os.getenv("DEBEMAIL", "[email protected]")

if not args_required:
args_before = frozenset([args.license_file, args.package_name, args.package_version])
args.license_file = args.license_file or config['license_file'].open()
args.package_name = args.package_name or Path.cwd().name
args.package_version = args.package_version or "0.0.1"
if args_before != frozenset([args.license_file, args.package_name, args.package_version]):
args = verify_auto_config(args)

# Fix homepage (TODO: figure out how to include this in the template file)
args.homepage = 'Homepage: {}'.format(args.homepage) if args.homepage else ''

# Create app dir:
package_dir = Path("{package_name}-{package_version}".format(**vars(args)))
if package_dir.exists():
if (input("Folder {} already exists. Delete? (y/n) ".format(package_dir)).lower() == "y"):
shutil.rmtree(str(package_dir))
package_dir.mkdir(exist_ok=True)

print("Copying templates... ", end='', flush=True)
try:
me = ZipFile(os.path.dirname(__file__), "r")
except:
me = ZipFile(os.path.dirname(__file__) + '/elf2deb.pyz' , "r")
for template in me.filelist:
if template.filename == os.path.basename(__file__):
continue # skip this file

target_filename = template.filename[len(TEMPLATE_DIR):]
if template.is_dir():
(package_dir / target_filename).mkdir(exist_ok=True)
else:
date = me.read(template).decode().format(**vars(args))
(package_dir / target_filename).write_text(date)

if args.license is not None:
copyright_file = package_dir / 'debian/copyright'
copyright_file.write_text(get_copyright(args))
elif args.license_file is not None:
copyright_file = package_dir / 'debian/copyright'
copyright_file.write_text(args.license_file.read())

# Make debian/rules executable:
mode = os.stat(str(package_dir / 'debian/rules')).st_mode
mode |= (mode & 0o444) >> 2 # copy R bits to X
os.chmod(str(package_dir / 'debian/rules'), mode)
print("done!")

print("Copying files... ", end="", flush=True)
makefile = open(str(package_dir / 'Makefile'), 'at')
for i, binary in enumerate(args.binary_files):
shutil.copy(binary, str(package_dir / os.path.basename(binary)))
if i > 0:
makefile.write('\tcp {} $(DESTDIR)$(PREFIX)/bin/\n'.format(binary))
makefile.close()
print("done!")
# Make sure package name is lowercase:
args.package_name = args.package_name.lower()

run(['dch', '--create', '--empty', '--distribution', 'unstable', '--package', args.package_name, '--newversion', args.package_version], cwd=str(package_dir))
run(['dch', '--append', 'Packaged using ELF2deb v{}'.format(__version__)], stderr=DEVNULL, cwd=str(package_dir))

print("Run:")
print(" * cd {}".format(package_dir))
print(" * vim debian/control # change description, dont add empty lines")
print(" * debuild -us -uc # remove -us -uc if you want to sign the deb file")
return args


if __name__ == "__main__":
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def find_version(version_file):
"Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Topic :: Software Development :: Build Tools",
Expand Down

0 comments on commit 6cc2a46

Please sign in to comment.