Пример #1
0
class DpkgTest(unittest.TestCase):
    def setUp(self):
        dpkgfile = os.path.join(os.path.dirname(__file__), TEST_DPKG_FILE)
        self.dpkg = Dpkg(dpkgfile)

    def test_get_versions(self):
        self.assertEqual(self.dpkg.epoch, 1)
        self.assertEqual(self.dpkg.upstream_version, '0.0.0')
        self.assertEqual(self.dpkg.debian_revision, 'test')

    def test_get_message_headers(self):
        self.assertEqual(self.dpkg.package, 'testdeb')
        self.assertEqual(self.dpkg.PACKAGE, 'testdeb')
        self.assertEqual(self.dpkg['package'], 'testdeb')
        self.assertEqual(self.dpkg['PACKAGE'], 'testdeb')
        self.assertEqual(self.dpkg.get('package'), 'testdeb')
        self.assertEqual(self.dpkg.get('PACKAGE'), 'testdeb')
        self.assertEqual(self.dpkg.get('nonexistent'), None)
        self.assertEqual(self.dpkg.get('nonexistent', 'foo'), 'foo')

    def test_missing_header(self):
        self.assertRaises(KeyError, self.dpkg.__getitem__, 'xyzzy')
        self.assertRaises(AttributeError, self.dpkg.__getattr__, 'xyzzy')

    def test_message(self):
        self.assertIsInstance(self.dpkg.message, type(Message()))
Пример #2
0
    def __get_packages(self):
        # get all files
        files = glob.glob( os.path.join(self.binary_path,"") + "*" + self.packageType )
        for fname in files:
            # extract the package information
            pkg_info = DpkgInfo(fname)

            # if arch is defined and does not match package, move on to the next
            if self.arch is not None:
                if str(pkg_info.headers['Architecture']) != self.arch:
                    continue

            # if --multiversion switch is passed, append to the list
            if self.multiversion==True:
                self.packageList.append(pkg_info)
            else:
                # finf if package is already in the list
                matchedItems = [(index,pkg) for (index,pkg) in enumerate(self.packageList) if self.packageList and pkg.headers['Package'] == pkg_info.headers['Package']]
                if len(matchedItems)==0:
                    # add if not
                    self.packageList.append(pkg_info)
                else:
                    # compare versions and add if newer
                    matchedIndex = matchedItems[0][0]
                    matchedItem = matchedItems[0][1]

                    dpkg = Dpkg(pkg_info.headers['Filename'])
                    if dpkg.compare_version_with(matchedItem.headers['Version']) == 1:
                        self.packageList[matchedIndex] = pkg_info
Пример #3
0
    def CreateDEB(self, bundle_id, recorded_version):
        """
        Creates a DEB from information stored in the "temp" folder.

        String bundle_id: The bundle id of the package to compress.
        """
        # TODO: Find a Python-based method to safely delete all DS_Store files.
        call(["find", ".", "-name", ".DS_Store", "-delete"],
             cwd=self.root + "temp/" +
             bundle_id)  # Remove .DS_Store. Kinda finicky.
        for file_name in os.listdir(self.root + "temp/" + bundle_id):
            if file_name.endswith(".deb"):
                # Check if the DEB is a newer version
                deb = Dpkg(self.root + "temp/" + bundle_id + "/" + file_name)
                if Dpkg.compare_versions(recorded_version, deb.version) == -1:
                    # Update package stuff
                    package_name = PackageLister.BundleIdToDirName(
                        self, bundle_id)
                    with open(
                            self.root + "Packages/" + package_name +
                            "/silica_data/index.json", "r") as content_file:
                        update_json = json.load(content_file)
                        update_json['version'] = deb.version
                        changelog_entry = input(
                            "The DEB provided for \"" + update_json['name'] +
                            "\" has a new version available (" +
                            recorded_version + " -> " + deb.version +
                            "). What changed in this version?\n(Add multiple lines"
                            +
                            " by using a newline character [\\n] and use valid Markdown syntax.): "
                        )
                        try:
                            update_json['changelog'].append({
                                "version":
                                deb.version,
                                "changes":
                                changelog_entry
                            })
                        except Exception:
                            update_json['changelog'] = {
                                "version": deb.version,
                                "changes": changelog_entry
                            }
                        return_str = json.dumps(update_json)
                        print("Updating package index.json...")
                        PackageLister.CreateFile(
                            self, "Packages/" + package_name +
                            "/silica_data/index.json", return_str)
                    pass
                DpkgPy.extract(
                    self, self.root + "temp/" + bundle_id + "/" + file_name,
                    self.root + "temp/" + bundle_id)
                os.remove(self.root + "temp/" + bundle_id + "/" + file_name)
                os.remove(self.root + "temp/" + bundle_id + "/control")
        else:
            # TODO: Update DpkgPy to generate DEB files without dependencies (for improved win32 support)
            call(["dpkg-deb", "-b", "-Zgzip", self.root + "temp/" + bundle_id],
                 cwd=self.root + "temp/")  # Compile DEB
Пример #4
0
 def test_split_full_version(self):
     self.assertEqual(Dpkg.split_full_version('00'), (0, '00', '0'))
     self.assertEqual(Dpkg.split_full_version('00-00'), (0, '00', '00'))
     self.assertEqual(Dpkg.split_full_version('0:0'), (0, '0', '0'))
     self.assertEqual(Dpkg.split_full_version('0:0-0'), (0, '0', '0'))
     self.assertEqual(Dpkg.split_full_version('0:0.0'), (0, '0.0', '0'))
     self.assertEqual(Dpkg.split_full_version('0:0.0-0'), (0, '0.0', '0'))
     self.assertEqual(Dpkg.split_full_version('0:0.0-00'), (0, '0.0', '00'))
Пример #5
0
    def test_dstringcmp(self):
        self.assertEqual(Dpkg.dstringcmp('~', '.'), -1)
        self.assertEqual(Dpkg.dstringcmp('~', 'a'), -1)
        self.assertEqual(Dpkg.dstringcmp('a', '.'), -1)
        self.assertEqual(Dpkg.dstringcmp('a', '~'), 1)
        self.assertEqual(Dpkg.dstringcmp('.', '~'), 1)
        self.assertEqual(Dpkg.dstringcmp('.', 'a'), 1)
        self.assertEqual(Dpkg.dstringcmp('.', '.'), 0)
        self.assertEqual(Dpkg.dstringcmp('0', '0'), 0)
        self.assertEqual(Dpkg.dstringcmp('a', 'a'), 0)

        # taken from
        # http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
        self.assertEqual(
            sorted(['a', '', '~', '~~a', '~~'], key=Dpkg.dstringcmp_key),
            ['~~', '~~a', '~', '', 'a'])
Пример #6
0
    def __init__(self, binary_path):
        self.binary_path = binary_path
        self.headers = {}
        pkg = Dpkg(self.binary_path)

        # build the information for the apt repo
        self.headers = pkg.headers
        self.headers['Filename'] = pkg.filename.replace("\\", '/')
        self.headers['Size'] = pkg.filesize
        self.headers['MD5sum'] = pkg.md5
        self.headers['SHA1'] = pkg.sha1
        self.headers['SHA256'] = pkg.sha256
Пример #7
0
def create_table_data(results, headers):
    table = []
    for name in sorted(results):
        for dist in sorted(results[name]):
            for comp in sorted(results[name][dist]):
                for arch in sorted(results[name][dist][comp]):
                    pkgs = results[name][dist][comp][arch]
                    pkgs.sort(
                        key=lambda x: Dpkg.compare_versions_key(x['version']))
                    for pkg in pkgs:
                        table.append([pkg[x] for x in headers])
    return table
Пример #8
0
 def test_get_alpha(self):
     self.assertEqual(Dpkg.get_alphas(''), ('', ''))
     self.assertEqual(Dpkg.get_alphas('0'), ('', '0'))
     self.assertEqual(Dpkg.get_alphas('00'), ('', '00'))
     self.assertEqual(Dpkg.get_alphas('0a'), ('', '0a'))
     self.assertEqual(Dpkg.get_alphas('a'), ('a', ''))
     self.assertEqual(Dpkg.get_alphas('a0'), ('a', '0'))
Пример #9
0
 def test_listify(self):
     self.assertEqual(Dpkg.listify('0'), ['', 0])
     self.assertEqual(Dpkg.listify('00'), ['', 0])
     self.assertEqual(Dpkg.listify('0a'), ['', 0, 'a', 0])
     self.assertEqual(Dpkg.listify('a0'), ['a', 0])
     self.assertEqual(Dpkg.listify('a00'), ['a', 0])
     self.assertEqual(Dpkg.listify('a'), ['a', 0])
 def getDebRepositoryLatestVersion(self, repository, packageName):
   repository = repository.split()
   URL = '{}/dists/{}'.format(repository[1], repository[2])
   packages = list()
   for i in range(3, len(repository)):
     packagesURL = '{}/{}/binary-amd64/Packages.gz'.format(URL, repository[i])
     data = zlib.decompress(requests.get(packagesURL).content, 16+zlib.MAX_WBITS).decode('UTF-8')
     for package in filter(None, data.split('\n\n')):
       packageDetails = self.convertDebPackagesSectionToYaml(package)
       if packageDetails['Package'] == packageName:
         packages.append(packageDetails)
   version = sorted(packages, key = lambda x:Dpkg.compare_versions_key(x['Version']), reverse=True)
   version = version[0]['Version']
   self.log.info('Package: {}, latest version: {}'.format(packageName, version))
   return version
Пример #11
0
class Package(object):
    """Represents a .deb package
    """
    def __init__(self, package_path):
        """Initialize instance properties
        """
        self.dpkg = Dpkg(package_path)
        self.headers = dict()
        self.get_package_meta()

    def get_package_meta(self):
        """Reads in the package metadata and incorporates it into
        the class
        """
        for key, value in HEADER_KEYS.items():
            self.headers[key] = self.dpkg.get(value)

    def render_packages_file(self):
        """Dumps out the data that would go in a Packages file
        for an apt repo
        """
        ret = list()

        for key, value in HEADER_KEYS.items():
            ret.append("{0}: {1}".format(key, self.headers[key]))
        ret.append('')

        return "\n".join(ret)

    def __getattribute__(self, name):
        """Make the dpkg header keys case-insensitive
        """
        headers = [x.lower() for x in HEADER_KEYS]
        if name.lower() in headers:
            for key in HEADER_KEYS.keys():
                if key.lower() == name.lower():
                    return self.headers[key]
        else:
            return object.__getattribute__(self, name)
Пример #12
0
def compareVersions(vulnPackages, vulnFixedVersion):
    fixedVer = vulnFixedVersion
    for ver in vulnPackages:
        #print("ver : ", ver)
        currVer = vulnPackages[ver]

    #print("currVer : ",  currVer)
    #print("fixedVer : ", fixedVer)
    compareResult = Dpkg.compare_versions(currVer, fixedVer)
    if compareResult == 0:
        printOutput.append(
            '\nThe package version in the product is the same as the Fixed Version ==> CONGRATULATIONS the product is NOT vulnerable.'
        )
    elif compareResult == 1:
        printOutput.append(
            '\nThe package version in the product is higher than the Fixed Version ==> CONGRATULATIONS the product is NOT vulnerable.'
        )
    elif compareResult == -1:
        printOutput.append(
            '\nThe package version in the product is LOWER than the Fixed Version ==> The product is VULNERABLE!'
        )
        return compareResult
Пример #13
0
 def parse_files(self):
     # dsc file
     dsc = Dsc(self.dsc)
     depends = set(safe_split(dsc.headers['Build-Depends']))
     self.product = dsc.headers['Source']
     self.binary = dsc.headers['Binary']
     self.version = dsc.headers['Version']
     self.package_list = dsc.headers['Package-List']
     # changelog
     debian_time = parse_changelog(self.changelog)
     if debian_time:
         self.timestamp = convert_debian_time_to_unix(debian_time)
     else:
         self.timestamp = -1
     # deb and udeb files
     for deb in self.debs:
         dpkg = Dpkg(deb)
         depends.update(safe_split(dpkg.headers['Depends']))
     # Set forge as debian because they declared as Debian packages
     debian_dependencies = [
         parse_dependency(dep, 'debian') for dep in depends
     ]
     self.dependencies.extend(debian_dependencies)
Пример #14
0
    def test_compare_revision_strings(self):
        # note that these are testing a single revision string, not the full
        # upstream+debian version.  IOW, "0.0.9-foo" is an upstream or debian
        # revision onto itself, not an upstream of 0.0.9 and a debian of foo.

        # equals
        self.assertEqual(Dpkg.compare_revision_strings('0', '0'), 0)
        self.assertEqual(Dpkg.compare_revision_strings('0', '00'), 0)
        self.assertEqual(Dpkg.compare_revision_strings('00.0.9', '0.0.9'), 0)
        self.assertEqual(Dpkg.compare_revision_strings('0.00.9-foo', '0.0.9-foo'), 0)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.9-1.00foo', '0.0.9-1.0foo'), 0)

        # less than
        self.assertEqual(Dpkg.compare_revision_strings('0.0.9', '0.0.10'), -1)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.9-foo', '0.0.10-foo'), -1)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.9-foo', '0.0.10-goo'), -1)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.9-foo', '0.0.9-goo'), -1)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.10-foo', '0.0.10-goo'), -1)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.9-1.0foo', '0.0.9-1.1foo'), -1)

        # greater than
        self.assertEqual(Dpkg.compare_revision_strings('0.0.10', '0.0.9'), 1)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.10-foo', '0.0.9-foo'), 1)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.10-foo', '0.0.9-goo'), 1)
        self.assertEqual(Dpkg.compare_revision_strings('0.0.9-1.0foo', '0.0.9-1.0bar'), 1)
Пример #15
0
 def test_get_digits(self):
     self.assertEqual(Dpkg.get_digits('00'), (0, ''))
     self.assertEqual(Dpkg.get_digits('0'), (0, ''))
     self.assertEqual(Dpkg.get_digits('0a'), (0, 'a'))
     self.assertEqual(Dpkg.get_digits('a'), (0, 'a'))
     self.assertEqual(Dpkg.get_digits('a0'), (0, 'a0'))
Пример #16
0
    def web_addpkg(self, reponame, name, version, fobj, dist):
        repo = get_repo(db(), reponame)
        dist = get_dist(db(), repo, dist)
        print("Dist:", dist)

        # - read f (write to temp storage if needed) and generate the hashes
        # - load with Dpkg to get name version and whatnot
        with TemporaryDirectory() as tdir:
            tmppkgpath = os.path.join(tdir, "temp.deb")
            with open(tmppkgpath, "wb") as fdest:
                fhashes = copyhash(fobj.file, fdest)
            fsize = os.path.getsize(tmppkgpath)

            p = Dpkg(tmppkgpath)
            pkgname = "{}_{}_{}.deb".format(p.message['Package'],
                                            p.message['Version'],
                                            p.message['Architecture'])

            #TODO keys can be duplicated in email.message.Message, does this cause any problems?
            fields = {key: p.message[key] for key in p.message.keys()}

            # repos/<reponame>/packages/f/foo.deb
            dpath = os.path.join(self.basepath, "repos", repo.name, "packages",
                                 dist.name, pkgname[0], pkgname)
            files = self.s3.list_objects(Bucket=self.bucket,
                                         Prefix=dpath).get("Contents")
            if files:
                print(f"will overwrite: {files}")

            pkg = AptPackage(repo=repo,
                             dist=dist,
                             name=p.message['Package'],
                             version=p.message['Version'],
                             arch=p.message['Architecture'],
                             fname=pkgname,
                             size=fsize,
                             **fhashes,
                             fields=json.dumps(fields))
            db().add(pkg)
            db().commit()

            try:
                with open(tmppkgpath, "rb") as f:
                    response = self.s3.put_object(Body=f,
                                                  Bucket=self.bucket,
                                                  Key=dpath)
                    assert (response["ResponseMetadata"]["HTTPStatusCode"] ==
                            200), f"Upload failed: {response}"
            except Exception:
                db().delete(pkg)
                db().commit()
                raise

        dist.dirty = True
        db().commit()
        self.regen_dist(dist.id)

        yield "package name: {}\n".format(pkgname)
        yield "package size: {}\n".format(fsize)
        yield "package message:\n-----------------\n{}\n-----------------\n".format(
            p.message)
        yield "package hashes: {}\n".format(fhashes)
Пример #17
0
def add(args, repodb, repo):
    """Add packages"""
    # we check this here before we risk uploading to s3
    if not validate_meta(args, repodb):
        return 1
    success = 0
    for fn in args.files:
        LOG.info('attempting to add file: %s', fn)
        if fn.endswith('.deb'):
            pkg = Dpkg(fn)
        elif fn.endswith('.dsc'):
            pkg = Dsc(fn)
        else:
            LOG.error('File "%s" is neither a deb nor a dsc files', fn)
            success += 1
            continue
        try:
            if isinstance(pkg, Dsc):
                LOG.info('attempting to add source to s3: %s',
                         os.path.basename(fn))
                repo.add_source(pkg,
                                dists=args.distribution,
                                overwrite=args.overwrite)
                LOG.info('attempting to add source to simpledb: %s',
                         os.path.basename(fn))
                repodb.add_source(pkg,
                                  dists=args.distribution,
                                  comps=args.component,
                                  overwrite=args.overwrite,
                                  auto_purge=args.auto_purge)
            else:
                arch = pkg.architecture
                repodb.check_valid_archs([arch])
                LOG.info('attempting to add package to s3: %s',
                         os.path.basename(pkg.filename))
                repo.add_package(pkg,
                                 dists=args.distribution,
                                 overwrite=args.overwrite)
                LOG.info('attempting to add package to simpledb: %s',
                         os.path.basename(pkg.filename))
                repodb.add_package(pkg,
                                   dists=args.distribution,
                                   comps=args.component,
                                   overwrite=args.overwrite,
                                   auto_purge=args.auto_purge)
            LOG.info('Successfully added %s to repoman!', fn)
        except InvalidArchitectureError:
            LOG.error('Package %s is built for the "%s" architecture, '
                      'which this repo is not currently configured to '
                      'serve; I will not add it.  You may which to run '
                      '"repoman repo add_architecture %s"', fn, arch, arch)
            success += 1
            continue
        except KeyExistsError:
            LOG.error('Package %s already exists in S3, you either want the '
                      '--overwrite flag or you want to move/copy the package '
                      'within the repo.  Skipping.', fn)
            success += 1
            continue
        except ItemExistsError:
            LOG.error('Package %s already exists in simpledb, you either want '
                      'the --overwrite flag or you want to move/copy the '
                      'package within the repo.  Skipping.', fn)
            success += 1
            continue
    if success > 0:
        LOG.error('Not all packages uploadeded successfully; inspect '
                  'the log output for errors.')
    return success
Пример #18
0
 def __init__(self, package_path):
     """Initialize instance properties
     """
     self.dpkg = Dpkg(package_path)
     self.headers = dict()
     self.get_package_meta()
Пример #19
0
 def test_get_upstream(self):
     self.assertEqual(Dpkg.get_upstream('00'), ('00', '0'))
     self.assertEqual(Dpkg.get_upstream('foo'), ('foo', '0'))
     self.assertEqual(Dpkg.get_upstream('foo-bar'), ('foo', 'bar'))
     self.assertEqual(Dpkg.get_upstream('foo-bar-baz'), ('foo-bar', 'baz'))
Пример #20
0
 def test_get_epoch(self):
     self.assertEqual(Dpkg.get_epoch('0'), (0, '0'))
     self.assertEqual(Dpkg.get_epoch('0:0'), (0, '0'))
     self.assertEqual(Dpkg.get_epoch('1:0'), (1, '0'))
     self.assertRaises(DpkgVersionError, Dpkg.get_epoch, '1a:0')
Пример #21
0
    def test_compare_versions(self):
        # "This [the epoch] is a single (generally small) unsigned integer.
        # It may be omitted, in which case zero is assumed."
        self.assertEqual(Dpkg.compare_versions('0.0.0', '0:0.0.0'), 0)
        self.assertEqual(Dpkg.compare_versions('0:0.0.0-foo', '0.0.0-foo'), 0)
        self.assertEqual(Dpkg.compare_versions('0.0.0-a', '0:0.0.0-a'), 0)

        # "The absence of a debian_revision is equivalent to a debian_revision
        # of 0."
        self.assertEqual(Dpkg.compare_versions('0.0.0', '0.0.0-0'), 0)
        # tricksy:
        self.assertEqual(Dpkg.compare_versions('0.0.0', '0.0.0-00'), 0)

        # combining the above
        self.assertEqual(Dpkg.compare_versions('0.0.0-0', '0:0.0.0'), 0)

        # explicitly equal
        self.assertEqual(Dpkg.compare_versions('0.0.0', '0.0.0'), 0)
        self.assertEqual(Dpkg.compare_versions('1:0.0.0', '1:0.0.0'), 0)
        self.assertEqual(Dpkg.compare_versions('0.0.0-10', '0.0.0-10'), 0)
        self.assertEqual(Dpkg.compare_versions('2:0.0.0-1', '2:0.0.0-1'), 0)
        self.assertEqual(Dpkg.compare_versions('0:a.0.0-foo', '0:a.0.0-foo'), 0)

        # less than
        self.assertEqual(Dpkg.compare_versions('0.0.0-0', '0:0.0.1'), -1)
        self.assertEqual(Dpkg.compare_versions('0.0.0-0', '0:0.0.0-a'), -1)
        self.assertEqual(Dpkg.compare_versions('0.0.0-0', '0:0.0.0-1'), -1)
        self.assertEqual(Dpkg.compare_versions('0.0.9', '0.0.10'), -1)
        self.assertEqual(Dpkg.compare_versions('0.9.0', '0.10.0'), -1)
        self.assertEqual(Dpkg.compare_versions('9.0.0', '10.0.0'), -1)

        # greater than
        self.assertEqual(Dpkg.compare_versions('0.0.1-0', '0:0.0.0'), 1)
        self.assertEqual(Dpkg.compare_versions('0.0.0-a', '0:0.0.0-1'), 1)
        self.assertEqual(Dpkg.compare_versions('0.0.0-a', '0:0.0.0-0'), 1)
        self.assertEqual(Dpkg.compare_versions('0.0.9', '0.0.1'), 1)
        self.assertEqual(Dpkg.compare_versions('0.9.0', '0.1.0'), 1)
        self.assertEqual(Dpkg.compare_versions('9.0.0', '1.0.0'), 1)

        # unicode me harder
        self.assertEqual(Dpkg.compare_versions(u'2:0.0.44-1', u'2:0.0.44-nobin'), -1)
        self.assertEqual(Dpkg.compare_versions(u'2:0.0.44-nobin', u'2:0.0.44-1'), 1)
        self.assertEqual(Dpkg.compare_versions(u'2:0.0.44-1', u'2:0.0.44-1'), 0)
Пример #22
0
 def setUp(self):
     dpkgfile = os.path.join(os.path.dirname(__file__), TEST_DPKG_FILE)
     self.dpkg = Dpkg(dpkgfile)
Пример #23
0
    def CreateDEB(self, bundle_id, recorded_version):
        """
        Creates a DEB from information stored in the "temp" folder.

        String bundle_id: The bundle id of the package to compress.
        String recorded_version: 
        Object tweak_release: A "tweak release" object.
        """
        # TODO: Find a Python-based method to safely delete all DS_Store files.
        call(["find", ".", "-name", ".DS_Store", "-delete"],
             cwd=self.root + "temp/" + bundle_id)  # Remove .DS_Store. Kinda finicky.
        for file_name in os.listdir(self.root + "temp/" + bundle_id):
            if file_name.endswith(".deb"):
                # Check if the DEB is a newer version
                deb = Dpkg(self.root + "temp/" + bundle_id + "/" + file_name)
                if Dpkg.compare_versions(recorded_version, deb.version) == -1:
                    # Update package stuff
                    package_name = PackageLister.BundleIdToDirName(self, bundle_id)
                    with open(self.root + "Packages/" + package_name + "/silica_data/index.json", "r") as content_file:
                        update_json = json.load(content_file)
                        update_json['version'] = deb.version
                        changelog_entry = input("The DEB provided for \"" + update_json['name'] +
                                                "\" has a new version available (" + recorded_version + " -> " +
                                                deb.version + "). What changed in this version?\n(Add multiple lines" +
                                                " by using newline characters [\\n\\n] and use valid Markdown syntax): "
                                                )

                        try:
                            update_json['changelog'].append(
                                {
                                    "version": deb.version,
                                    "changes": changelog_entry
                                }
                            )
                        except Exception:
                            # Make it a list!
                            update_json['changelog'] = []

                            update_json['changelog'].append(
                                {
                                    "version": deb.version,
                                    "changes": changelog_entry
                                }
                            )

                        # A small note: We already created the variables that contain the changelogs and, to
                        # make matters worse, all the web assets. The only way to mitigate this is to re-create the
                        # tweak_release variable again, which wrecks a lot of things (ie runtime).
                        # A Silica rewrite is required to properly fix this bug.
                        print("\nA small warning about adding changelogs mid-run:\n")
                        print("Due to some less-than-ideal design decisions with Silica, for the changelog to show")
                        print("up, you're going to have to run Silica again. Yes, I know this is annoying, and a proper")
                        print("solution is in the works, but the under-the-hood changes that'll be needed to fix")
                        print("it properly would require a rewrite [see issue #22].\n")
                        print("I'm deeply sorry about this.\n    - Shuga.\n")

                        # Get human-readable folder name
                        folder = PackageLister.BundleIdToDirName(self, bundle_id)
                        deb_path = self.root + "Packages/" + folder + "/" + file_name
                        # Extract Control file and scripts from DEB
                        DpkgPy.control_extract(self, deb_path, self.root + "Packages/" + folder +
                                               "/silica_data/scripts/")
                        # Remove the Control; it's not needed.
                        os.remove(self.root + "Packages/" + folder + "/silica_data/scripts/Control")
                        if not os.listdir(self.root + "Packages/" + folder + "/silica_data/scripts/"):
                            os.rmdir(self.root + "Packages/" + folder + "/silica_data/scripts/")

                        return_str = json.dumps(update_json)
                        print("Updating package index.json...")
                        PackageLister.CreateFile(self, "Packages/" + package_name +
                                                 "/silica_data/index.json", return_str)
                    pass
                DpkgPy.extract(self, self.root + "temp/" + bundle_id + "/" + file_name, self.root + "temp/" + bundle_id)
                try:
                    os.remove(self.root + "temp/" + bundle_id + "/" + file_name)
                except:
                    pass
                try:
                    os.remove(self.root + "temp/" + bundle_id + "/control")
                except:
                    pass
        else:
            # TODO: Update DpkgPy to generate DEB files without dependencies (for improved win32 support)
            # If the version is consistent, then assume the package is unchanged. Don't regenerate it.
            try:
                # Check for a DEB that already exists.
                docs_deb = Dpkg(self.root + "docs/pkg/" + bundle_id + ".deb")
                if docs_deb.version == recorded_version:
                    shutil.copy(self.root + "docs/pkg/" + bundle_id + ".deb", self.root + "temp/" + bundle_id + ".deb")
                    call_result = 0;
                else:
                    # Sneaky swap.
                    call_result = call(["dpkg-deb", "-b", "-Zgzip", self.root + "temp/" + bundle_id], cwd=self.root + "temp/")  # Compile DEB
            except:
                # Create the DEB again.
                call_result = call(["dpkg-deb", "-b", "-Zgzip", self.root + "temp/" + bundle_id], cwd=self.root + "temp/")  # Compile DEB
            if call_result != 0:
                # Did we run within WSL?
                if "Microsoft" in platform.release():
                    PackageLister.ErrorReporter(self, "Platform Error!", "dpkg-deb failed to run. "
                    "This is likely due to improper configuration of WSL. Please check the Silcia README for "
                    "how to set up WSL for dpkg-deb.")
                else:
                    PackageLister.ErrorReporter(self, "DPKG Error!", "dpkg-deb failed to run. "
                    "This could be due to a faulty system configuration.")
Пример #24
0
    def CheckForSilicaData(self):
        """
        Ensures that a silica_data file exists and if it doesn't, try to create one with as much data as we have.
        If there is a DEB file, it will take data from its CONTROL file. It will also auto-update the version number.
        If there is no DEB file, it will use the name of the folder, version 1.0.0, try to guess some dependencies,
            and add some placeholder data.
        :return:
        """
        for folder in os.listdir(self.root + "Packages"):
            if folder.lower() != ".ds_store":
                if not os.path.isdir(self.root + "Packages/" + folder + "/silica_data"):
                    print("It seems like the package \"" + folder + "\" is not configured. Let's set it up!")
                    is_deb = False
                    deb_path = ""
                    try:
                        for file_name in os.listdir(self.root + "Packages/" + folder):
                            if file_name.endswith(".deb"):
                                is_deb = True
                                deb_path = self.root + "Packages/" + folder + "/" + file_name
                    except Exception:
                        PackageLister.ErrorReporter(self, "Configuration Error!", "Please put your .deb file inside of "
                            "its own folder. The \"Packages\" directory should be made of multiple folders that each "
                            "contain data for a single package.\n Please fix this issue and try again.")

                    # This will be the default scaffolding for our package. Eventually I'll neuter it to only be the
                    # essential elements; it's also kinda a reference to me.
                    output = {
                        "bundle_id": "co.shuga.silica.unknown",
                        "name": "Unknown Package",
                        "version": "1.0.0",
                        "tagline": "An unknown package.",
                        "homepage": "https://shuga.co/",
                        "developer": {
                            "name": "Unknown",
                            "email": "*****@*****.**"
                        },
                        "maintainer": {
                            "name": "Unknown",
                            "email": "*****@*****.**"
                        },
                        "section": "Themes",

                        "works_min": "8.0",
                        "works_max": "13.0",
                        "featured": "false"
                    }

                    if is_deb:
                        print("Extracting data from DEB...")
                        deb = Dpkg(deb_path)
                        output['name'] = deb.headers['Name']
                        output['bundle_id'] = deb.headers['Package']
                        try:
                            output['tagline'] = deb.headers['Description']
                        except Exception:
                            output['tagline'] = input("What is a brief description of the package? ")
                        try:
                            output['homepage'] = deb.headers['Homepage']
                        except Exception:
                            pass
                        try:
                            remove_email_regex = re.compile('<.*?>')
                            output['developer']['name'] = remove_email_regex.sub("", deb.headers['Author'])
                        except Exception:
                            output['developer']['name'] = input("Who originally made this package? This may be"
                                                                " your name. ")
                        output['developer']['email'] = input("What is the original author's email address? ")
                        try:
                            remove_email_regex = re.compile('<.*?>')
                            output['maintainer']['name'] = remove_email_regex.sub("", deb.headers['Maintainer'])
                        except Exception:
                            output['maintainer']['name'] = input("Who maintains this package now?"
                                                                 " This is likely your name. ")
                        output['maintainer']['email'] = input("What is the maintainer's email address? ")
                        try:
                            output['sponsor']['name'] = remove_email_regex.sub("", deb.headers['Sponsor'])
                        except Exception:
                            pass
                        try:
                            output['dependencies'] = deb.headers['Depends']
                        except Exception:
                            pass
                        try:
                            output['section'] = deb.headers['Section']
                        except Exception:
                            pass
                        try:
                            output['version'] = deb.headers['Version']
                        except Exception:
                            output['version'] = "1.0.0"
                        try:
                            output['conflicts'] = deb.headers['Conflicts']
                        except Exception:
                            pass
                        try:
                            output['replaces'] = deb.headers['Replaces']
                        except Exception:
                            pass
                        try:
                            output['provides'] = deb.headers['Provides']
                        except Exception:
                            pass
                        try:
                            output['build_depends'] = deb.headers['Build-Depends']
                        except Exception:
                            pass
                        try:
                            output['recommends'] = deb.headers['Recommends']
                        except Exception:
                            pass
                        try:
                            output['suggests'] = deb.headers['Suggests']
                        except Exception:
                            pass
                        try:
                            output['enhances'] = deb.headers['Enhances']
                        except Exception:
                            pass
                        try:
                            output['breaks'] = deb.headers['Breaks']
                        except Exception:
                            pass
                        try:
                            output['tags'] = deb.headers['Tag']
                        except Exception:
                            pass
                        try:
                            output['suggests'] = deb.headers['Suggests']
                        except Exception:
                            pass
                        # These still need data.
                        output['works_min'] = input("What is the lowest iOS version the package works on? ")
                        output['works_max'] = input("What is the highest iOS version the package works on? ")
                        output['featured'] = input("Should this package be featured on your repo? (true/false) ")
                        set_tint = input("What would you like this package's tint color to be? To keep it at"
                                         " the default, leave this blank: ")
                        if set_tint != "":
                            output['tint'] = set_tint
                        print("All done! Please look over the generated \"index.json\" file and consider populating the"
                              " \"silica_data\" folder with a description, screenshots, and an icon.")
                        # Extract Control file and scripts from DEB
                        DpkgPy.control_extract(self, deb_path, self.root + "Packages/" + folder +
                                               "/silica_data/scripts/")
                        # Remove the Control; it's not needed.
                        os.remove(self.root + "Packages/" + folder + "/silica_data/scripts/Control")
                        if not os.listdir(self.root + "Packages/" + folder + "/silica_data/scripts/"):
                            os.rmdir(self.root + "Packages/" + folder + "/silica_data/scripts/")
                    else:
                        print("Estimating dependencies...")
                        # Use the filesystem to see if Zeppelin, Anemone, LockGlyph, XenHTML, and similar.
                        # If one of these are found, set it as a dependency.
                        # If multiple of these are found, use a hierarchy system, with Anemone as the highest priority,
                        # for determining the category.
                        output['dependencies'] = ""
                        output['section'] = "Themes"

                        if os.path.isdir(self.root + "Packages/" + folder + "/Library/Zeppelin"):
                            output['section'] = "Themes (Zeppelin)"
                            output['dependencies'] += "com.alexzielenski.zeppelin, "

                        if os.path.isdir(self.root + "Packages/" + folder + "/Library/Application Support/LockGlyph"):
                            output['section'] = "Themes (LockGlyph)"
                            output['dependencies'] += "com.evilgoldfish.lockglypgh, "

                        if os.path.isdir(self.root + "Packages/" + folder + "/var/mobile/Library/iWidgets"):
                            output['section'] = "Widgets"
                            output['dependencies'] += "com.matchstic.xenhtml, "

                        if os.path.isdir(self.root + "Packages/" + folder + "/Library/Wallpaper"):
                            output['section'] = "Wallpapers"

                        if os.path.isdir(self.root + "Packages/" + folder + "/Library/Themes"):
                            output['section'] = "Themes"
                            output['dependencies'] += "com.anemonetheming.anemone, "

                        if output['dependencies'] != "":
                            output['dependencies'] = output['dependencies'][:-2]

                        repo_settings = PackageLister.GetRepoSettings(self)
                        # Ask for name
                        output['name'] = input("What should we name this package? ")
                        # Automatically generate a bundle ID from the package name.
                        domain_breakup = repo_settings['cname'].split(".")[::-1]
                        only_alpha_regex = re.compile('[^a-zA-Z]')
                        machine_safe_name = only_alpha_regex.sub("", output['name']).lower()
                        output['bundle_id'] = ".".join(str(x) for x in domain_breakup) + "." + machine_safe_name
                        output['tagline'] = input("What is a brief description of the package? ")
                        output['homepage'] = "https://" + repo_settings['cname']
                        # I could potentially default this to what is in settings.json but attribution may be an issue.
                        output['developer']['name'] = input("Who made this package? This is likely your name. ")
                        output['developer']['email'] = input("What is the author's email address? ")
                        output['works_min'] = input("What is the lowest iOS version the package works on? ")
                        output['works_max'] = input("What is the highest iOS version the package works on? ")
                        output['featured'] = input("Should this package be featured on your repo? (true/false) ")
                    PackageLister.CreateFolder(self, "Packages/" + folder + "/silica_data/")
                    PackageLister.CreateFile(self, "Packages/" + folder + "/silica_data/index.json", json.dumps(output))
Пример #25
0
    def CreateDEB(self, bundle_id, recorded_version):
        """
        Creates a DEB from information stored in the "temp" folder.

        String bundle_id: The bundle id of the package to compress.
        String recorded_version: 
        Object tweak_release: A "tweak release" object.
        """
        # TODO: Find a Python-based method to safely delete all DS_Store files.
        call(["find", ".", "-name", ".DS_Store", "-delete"],
             cwd=self.root + "temp/" + bundle_id)  # Remove .DS_Store. Kinda finicky.
        for file_name in os.listdir(self.root + "temp/" + bundle_id):
            if file_name.endswith(".deb"):
                # Check if the DEB is a newer version
                deb = Dpkg(self.root + "temp/" + bundle_id + "/" + file_name)
                if Dpkg.compare_versions(recorded_version, deb.version) == -1:
                    # Update package stuff
                    package_name = PackageLister.BundleIdToDirName(self, bundle_id)
                    with open(self.root + "Packages/" + package_name + "/silica_data/index.json", "r") as content_file:
                        update_json = json.load(content_file)
                        update_json['version'] = deb.version
                        changelog_entry = input("The DEB provided for \"" + update_json['name'] +
                                                "\" has a new version available (" + recorded_version + " -> " +
                                                deb.version + "). What changed in this version?\n(Add multiple lines" +
                                                " by using newline characters [\\n\\n] and use valid Markdown syntax): "
                                                )
                        try:
                            update_json['changelog'].append({
                                "version": deb.version,
                                "changes": changelog_entry
                            })
                        except Exception:
                            update_json['changelog'] = {
                                "version": deb.version,
                                "changes": changelog_entry
                            }

                        # Get human-readable folder name
                        folder = PackageLister.BundleIdToDirName(self, bundle_id)
                        deb_path = self.root + "Packages/" + folder + "/" + file_name
                        # Extract Control file and scripts from DEB
                        DpkgPy.control_extract(self, deb_path, self.root + "Packages/" + folder +
                                               "/silica_data/scripts/")
                        # Remove the Control; it's not needed.
                        os.remove(self.root + "Packages/" + folder + "/silica_data/scripts/Control")
                        if not os.listdir(self.root + "Packages/" + folder + "/silica_data/scripts/"):
                            os.rmdir(self.root + "Packages/" + folder + "/silica_data/scripts/")

                        return_str = json.dumps(update_json)
                        print("Updating package index.json...")
                        PackageLister.CreateFile(self, "Packages/" + package_name +
                                                 "/silica_data/index.json", return_str)
                    pass
                DpkgPy.extract(self, self.root + "temp/" + bundle_id + "/" + file_name, self.root + "temp/" + bundle_id)
                os.remove(self.root + "temp/" + bundle_id + "/" + file_name)
                os.remove(self.root + "temp/" + bundle_id + "/control")
        else:
            # TODO: Update DpkgPy to generate DEB files without dependencies (for improved win32 support)
            # If the version is consistent, then assume the package is unchanged. Don't regenerate it.
            try:
                docs_deb = Dpkg(self.root + "docs/pkg/" + bundle_id + ".deb")
                if docs_deb.version == recorded_version:
                    shutil.copy(self.root + "docs/pkg/" + bundle_id + ".deb", self.root + "temp/" + bundle_id + ".deb")
                    call_result = 0;
                else:
                    # Sneaky swap.
                    call_result = call(["dpkg-deb", "-b", "-Zgzip", self.root + "temp/" + bundle_id], cwd=self.root + "temp/")  # Compile DEB
            except:
                call_result = call(["dpkg-deb", "-b", "-Zgzip", self.root + "temp/" + bundle_id], cwd=self.root + "temp/")  # Compile DEB
            if call_result != 0:
                # Did we run within WSL?
                if "Microsoft" in platform.release():
                    PackageLister.ErrorReporter(self, "Platform Error!", "dpkg-deb failed to run. "
                    "This is due to improper configuration of WSL. Please check the Silcia README for "
                    "how to set up WSL for dpkg-deb.")
                else:
                    PackageLister.ErrorReporter(self, "Platform Error!", "dpkg-deb failed to run. "
                    "This may be due to a faulty system configuration.")